原帖:
——总结自《C PRIMER PLUS》
直接看三个例子:
inta=4;
printf("%f%e\n",a,a);
floatb=4;
printf("%f%e\n",b,b);
intn1=-1,n2=-2,n3=-3;
printf("%lld%lld%lld\n",n1,n2,n3);
运行结果为:
可见,输出结果并非像预期的那样会自行转换数据类型!
原因在于printf后边的变量以栈的方式存储,而%f、%lld等转换说明符的操作方式是从栈中读取该符号对应数据类型的字节数,并不关心后边对应的数据类型具体是什么!
比如%f,要读取8字节,而a存到堆栈中只有4字节,当然会出现错误!
再看一个例子:
inta=4;
doubleadd=361263.321;
printf("%f%d\n",a,add);
输出结果:
原因:1091964093的十六进制表示:
再看看double add在内存中的存储:
恰好是add的后4字节!这样就不难理解上面的过程了。
——printf首先读后边的数据进栈,从右向左压栈。然后出栈处理转换说明符%d等
具体过程是这样的:先把double add进栈8字节,再把int a进栈4字节,
这时候栈底4字节存储的是41 16 0c bd;
然后输出第一个%f,取出8字节,取到了栈底4字节的前边;
然后操作%d,取出4字节,即之前所说的41 16 0c bd
/*—————————————————————————————*/
下图是截自原书,可以更好地理解这里面的过程!
其中,上面是栈底,n4先入栈,n1最后入栈;
输出先输出第一个%ld,读取的是float n1(4字节);
接下来的两个%ld读取n2的前一半和后一半;
最后一个%ld读取的是n3
(当然,为了保证正确的输出,可以在输出前转换数据类型,这样不会有问题!)
举一个例子验证这个问题
总结一下,printf语句一定要注意输出格式和变量类型的匹配,不然会出现莫名奇妙的错误。