调用
printf("%.1f%s",0.0,"a");
的输出是
0.0a
而调用
printf("%.1f%s",0,"a");
的输出是
0.0@
第二个输出的字符并不是“a”(ASCII码97),而是“@”(ASCII码64),在VC 6下。
为什么?具体原因。
解答:
1,查看两句话的反汇编
1) printf("%.1f,%s", 0.0,"a");
004113BE mov esi,esp
004113C0 push offset string "a" (41581Ch)
004113C5 sub esp,8
004113C8 fldz
//将0.0压入到st(0)中
004113CA fstp qword ptr [esp]
//将st(0)中的内容存放到qword ptr [esp]指定的位置(4*4个字节=8个字节)
004113CD push offset string "%.1f,%s" (415800h)
004113D2 call dword ptr [__imp__printf (4182BCh)]
2) printf("%.1f,%s", 0,"a");
004113BE mov esi,esp
004113C0 push offset string "a" (41580Ch)
004113C5 push 0
004113C7 push offset string "%.1f,%s" (415800h)
004113CC call dword ptr [__imp__printf (4182BCh)]
我们可以得知编译器把"0.0"解释成8个字节的类型,而把"0"解释成4个字节的类型,因此在对0.0和0入栈的过程中导致了栈内容的不一致,如下图所示,而printf的格式字符串%f是把参数解释成4个字节的类型,因此,它通过弹栈取出的只有4个字节,故此导致下一个参数(这里是字符串变量)的地址出现偏差,因而取出该地址下的内容也就不正确了,是未确定的。
2,顺便记录一下printf的实现
printf是个函数,其参数是valist类型的,也就是说参数是不固定的,它的实现是
* Algorithm:
* The format string is parsed by using a finite state automaton
* based on the current state and the current character read from
* the format string. Thus, looping is on a per-character basis,
* not a per conversion specifier basis. Once the format specififying
* character is read, output is performed.
一个有限自动机来解析格式字符串的。格式串之后就是格式中对应的参数。这些参数是通过一个va_arg的宏来获取的,根据类型的不同返回的值也就不同。