void main()
{
double * p;
int * k;
int t=55;
p = &t;
k = &t;
printf("%d %d\n",*p,*k);
}
为什么输出 *p=55 *k=4201104
为什么*k
变成了内存地址呢? 如果先输出*k
后输出*p
结果是正常的 求解
void main()
{
double * p;
int * k;
int t=55;
p = &t;
k = &t;
printf("%d %d\n",*p,*k);
}
为什么输出 *p=55 *k=4201104
为什么*k
变成了内存地址呢? 如果先输出*k
后输出*p
结果是正常的 求解
输出的时候应该会去转换 通过内存地址找到对应的55.当先打印K的时候。因为K 也是int指针,所以指向了t=55的内存地址,然后P的地址也是K的地址所以都是55. 而如果先打印P的话。因为P是double. 而t=55是int 指针,类型不对。他会截断/调整。
因为int是4字节,double是8字节,从int*地址读取8字节内存会带有4字节垃圾数据。printf接收到的参数内存是char*/55/..../55
,把垃圾数据[....]解析成整型自然会得到错误的结果。如果仅传递低4字节就可以得到正确的结果了printf("%d %d\n",*(int*)p,*k);
C 语言有一种叫做未定义行为(Undefined behavior)的东西。意思是,你不要这样写,如果你这样写了,我就不能保证会发生什么了。
这个,使用一个
double
指针去解引用一个int
变量是一个未定义行为(strict aliasing rule)。[[ Note
使用
%d
来输出一个double
(*p
) 是另一个。C11(draft) 7.21.6.1(THe fprintf function)/9End Note]]
换句话说,未定义行为是一些编译器无法检测的“错误”。(现在的编译器已经可以检测到一些了,比如用
%d
输出double
在适当的编译选项下,会被 gcc 据掉。)如果程序里有未定义行为,那么程序结果就不能保证/不可预测。C 语言只能保证没有未定义行为的程序有可预测的结果。保证程序没有未定义行为是程序员的责任。