一、问题描述
二、进一步说明
请仔细注意看,有如下奇怪的现象
int a=5;
floatx=a; //这里转换是没有问题的,%f打印x是 5.000000
printf("%d\n",a);
printf("%f\n",a); //输出为什么是0.000000? -----问题1
printf("%f\n",x);
printf("%d\n",x); //输出为什么是0? -----问题2
printf("%f,%f\n",a,x); //输出都是0.000000 为什么? ----问题3
printf("%f,%f\n",x,a); //调换一下a,x的顺序,正常了,为什么? ----问题4
printf("%d,%f\n",a,x);
getchar();
return0;
三、printf()函数的原理解释
明白这些问题首先需要明白printf()函数的工作原理。
printf()维持了一个需要打印的变量栈,默认情况下,参数进栈的顺序是由右向左的,因此,参数进栈以后的内存模型如下图所示:
打印的时候,printf按照字符转换说明符规定的格式从低地址开始提取数据,直到参数打印完。
比如遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()其实不知道参数的个数,它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址的内容。
这样一来,printf()其实存在安全隐患——没错,它会强行读取内存的数据当作正常数据输出,没有边界检测————很有可能产生堆溢出!
比如这样的代码:
char string[]="Hello World!";
printf("String: %s ,强行再读一次: %#p\n", string);
printf("String: %s ,强行再读一次: %#s\n", string);
输出如下:
String:Hello World! , 强行再读一次: 0X001C1073
String: Hello World! ,强行再读一次: 閮
三、问题解释
(1) 问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节,a只有4字节,提取出来的数占了float表示法的指数部分,尾数部分为0,所以最终是0
(2) 问题2:printf("%d\n",x) 输出为什么是0?
答:%d 提取4字节,x有8字节,提取出来的数实际上是float表示法的指数部分(恰好是0),所以最终是0
(3) 问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?
答:参照问题1的解释,提取了八字节后,后面的已经乱了
(4) 问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?
答:这是正常的情况而已。