在printf时:如果以%f格式输出,将输出8个字节(scanf输入时,%f是4个字节)
在参数入栈时如果是float型或者double型 直接入栈8个字节,此时输出及后续输出都没问题
但如果参数小于8个字节且不是float型:比如int shor int ,就会扩展符号位,成为4个字节再入栈,但是输出的是8个字节,所以会读取其他参数的入栈结果
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { int a = 3; int b = 5; printf("%f %d\n", a, b); return 0; }
在linux下的gcc输出结果是: 0.000000 134513801 -->后面这个值是一个无用值,比如int x; printf("%d\n", x) -->输出的就是:134513801
在vs2013下的输出结果是:0.000000 0 vs中对int x; printf("%d\n",x)会出现错误,因为x未初始化,
-->上述入栈结果是(十六进制):
栈顶 栈底
03 00 00 00 05 00 00 00
-->%f 读取8个字节,直接把b的入栈结果读走了
符号位 阶码 尾数 总位数
短浮点数 1 8 23 32
长浮点数 1 11 52 64
在32位浮点数的读取中:从内存中读出0x 03 00 00 00后,因为是小端模式,所以变成0x 00 00 00 03
0 000 0000 0 000 0000 0000 0000 0000 0011
第一个0是符号位:表正
第2到9位是阶码,32位浮点数的指数偏移量是127, 所以此处是-127
后面的均为小数点后面的:小数点前为1
-->(1 + 2^(-22) + 2^(-23)) * 2^(-127)
趋近于0;
在64位浮点数中:则阶码偏移量为:2^(10) - 1
例1:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { int a = 3; int b = 0xffffffff; printf("%f %d\n", a, b); return 0; }
在gcc中结果为:-nan 134513801 -->-nan表示负无穷大
在VS2013中结果为:-1.#QNAN0 0
printf的栈中: 03 00 00 00 ff ff ff ff
-->按%f读取的时候:ff ff ff ff 00 00 00 03
-->按浮点数解析相应的位!
例2:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { int a = 0x10000003; int b = 0x40110000; printf("%f %d\n", a, b); int c[2]; c[0] = 0x10000003; c[1] = 0x40110000; double d = *(double*)c; printf("%f\n", d); return 0; }
gcc中:
分析:
在第一个printf的栈中: 03 00 00 10 00 00 11 40
-->以%f读出时出栈结果:0x 40 11 00 00 10 00 00 03
-->64位浮点数解析:0100 0000 0001 0001 0000 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 0011
符号位:0
阶码:100 0000 0001 -->11位 -->减去偏移量:2^(10) -1 -->结果为2
小数位:0001 0000 0000 0000 0000 00....
最后大小:(1 + 2^(-4) + 2^(-52) + 2^(-51) + 2^(-24)) * 2^(2)
-->2进制:100 + 2^(-2) -->4.250000
例3:
反过来看
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { int a = 5; float b = 3.0; printf("%d %d\n" , a, b); return 0; }
输出结果: 5 0
b虽然是4个字节的float型,但是在入栈时会变换为8个字节的fdouble型
--->float型的3.0的表示:0x 40 40 00 00
-->内存中: 00 00 40 40
-->printf输出时入栈变为扩展8个字节的double型: 00 00 00 00 00 00 08 40
-->此时printf的栈中:
05 00 00 00 00 00 00 00 00 00 08 40
-->以%d格式输出两次: 5 0
32位的float型的3二进制码: 0 100 0000 0 100 0000 0000 0000 0000 0000
64位的double型3的二进制: 0 100 0000 0000 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
对比: 32 64
符号位 0 0
阶码: 100 0000 0 100 0000 0000 -->64位在32位后面添加了3个0
尾数 : 100..... 100.... -->64位在32位后面添加了29个0
总结:
printf 以%f格式输出时输出8个字节,float类型输出时入printf的栈要扩展为double型的8个字节!
printf的返回值为实际控制输出的字符数(不包括字符串末尾的‘\0‘),