关于整形和浮点型的格式输出
一个很好玩的现象:
源代码:
#include <stdio.h> int main() { int a = 10000; float b = 55.55; int c = 9988; printf("a : %f \n",a); printf("c : %f \n",c); printf("b : %d \n",(int)b); printf("a : %f \n",a); printf("c : %f \n",c); printf("b : %f \n",b); printf("a : %f \n",a); printf("c : %f \n",c); printf("b : %d \n",b); return 0; }
输出:
root@Ivy-debian-64:/home/zhangxu# ./a.out a : 0.000000 c : 0.000000 b : 55 a : 0.000000 c : 0.000000 b : 55.549999 a : 55.549999 c : 55.549999 b : -1645481984 root@Ivy-debian-64:/home/zhangxu# ./a.out a : 0.000000 c : 0.000000 b : 55 a : 0.000000 c : 0.000000 b : 55.549999 a : 55.549999 c : 55.549999 b : 1511591936
结果很奇怪,注意a、b以同样的格式输出时的不同结果。
1 .file "double_int.c" 2 .section .rodata 3 .LC1: 4 .string "a : %f \n" 5 .LC2: 6 .string "c : %f \n" 7 .LC3: 8 .string "b : %d \n" 9 .LC4: 10 .string "b : %f \n" 11 .text 12 .globl main 13 .type main, @function 14 main: 15 .LFB0: 16 .cfi_startproc 17 pushq %rbp 18 .cfi_def_cfa_offset 16 19 .cfi_offset 6, -16 20 movq %rsp, %rbp 21 .cfi_def_cfa_register 6 22 subq $16, %rsp 23 movl $10000, -4(%rbp) 24 movl .LC0(%rip), %eax 25 movl %eax, -8(%rbp) 26 movl $9988, -12(%rbp) 27 movl -4(%rbp), %eax 28 movl %eax, %esi //参数 %esi = 10000 29 movl $.LC1, %edi //格式串 %edi 30 movl $0, %eax //0代表参数为整型 %eax (只是猜测,含义上不明确) 31 call printf //输出 0.000000 32 33 movl -12(%rbp), %eax 34 movl %eax, %esi 35 movl $.LC2, %edi 36 movl $0, %eax 37 call printf //同上 38 39 movss -8(%rbp), %xmm0 //单精度浮点数移动指令 40 cvttss2si %xmm0, %eax //单精度浮点数转换成整型,带截断,装入%eax 41 movl %eax, %esi //参数 %esi = 55 42 movl $.LC3, %edi 43 movl $0, %eax 44 call printf 45 46 movl -4(%rbp), %eax 47 movl %eax, %esi 48 movl $.LC1, %edi 49 movl $0, %eax 50 call printf //xmm0中没有值,依然输出0.000000
51 movl -12(%rbp), %eax 52 movl %eax, %esi 53 movl $.LC2, %edi 54 movl $0, %eax 55 call printf //同 line 50 56 57 movss -8(%rbp), %xmm0 58 cvtps2pd %xmm0, %xmm0 //单精度转换成双精度,装入xmm0 59 movl $.LC4, %edi //格式串 60 movl $1, %eax //1代表参数为浮点型 %eax 61 call printf //输出55.549999 62 63 movl -4(%rbp), %eax 64 movl %eax, %esi 65 movl $.LC1, %edi 66 movl $0, %eax 67 call printf //输出55.549999 68 69 movl -12(%rbp), %eax 70 movl %eax, %esi 71 movl $.LC2, %edi 72 movl $0, %eax 73 call printf //输出55.549999 74 75 movss -8(%rbp), %xmm0 76 cvtps2pd %xmm0, %xmm0
# movl $5555, %esi 77 movl $.LC3, %edi 78 movl $1, %eax 79 call printf //输出任意值 80 81 movl $0, %eax 82 leave 83 .cfi_def_cfa 7, 8 84 ret 85 .cfi_endproc 86 .LFE0: 87 .size main, .-main 88 .section .rodata 89 .align 4 90 .LC0: 91 .long 1113469747 92 .ident "GCC: (Debian 4.7.2-5) 4.7.2" 93 .section .note.GNU-stack,"",@progbits
可能的原因如下,
如果格式串中有“%f”时,printf就会从xmm中读出相应的值,所以如果xmm中没有正确的值,就会输出0.000000。如果有,就会用此时xmm中的值,当成输入,这就是line 56、line 73输出55.549999(精度问题,如果是双精度浮点会输出55.550000)的原因。因为之前用“%f”输出b的时候,将xmm赋值了。
如果格式串中有“%d”时,printf就从esi中读取相应的值,所以line 79会输出任意值,因为此时esi的值可能是任意的。如果在line 76和 line 77之间人为地给esi赋值为5555,就会输出b:5555。
单精度和双精度的情况不同。
参考: