vs中的printf
最近有位兄弟在群里发了这样一个问题
我开始没意识过来,后来自己算了一遍,算出为“3 6”,这问题就有点大了,开始百度吧。
查了一圈,发现了第一个问题,printf的计算顺序是从右往左的(和栈有关,先入后出),于是再次计算,发现还是不对,第二次算出为“4 2”。所有又是哪里出问题了呢。
忽然想起,vs有反汇编的功能,那我直接看汇编代码看看问题出在哪
(vs的编译器是cl,不同编译器将会有不同结果)
嗯,主体部分都在这,我们一条一条看
char a = 1;
004018E8 mov byte ptr [a],1 ;把立即数1送到a所指向的地址单元(一个字节),ptr表示指针,也就是给变量a赋值
printf("%d %d", a += 2, a *= 2);
004018EC movsx eax,byte ptr [a] ;将变量a的值赋给eax寄存器
004018F0 shl eax,1 ;eax寄存器左移一位,也就是a*2
004018F2 mov byte ptr [a],al ;al表示eax寄存器的低八位,是最低的八位,eax为32位的,这句的意思是把eax的值又赋给a
004018F5 movsx ecx,byte ptr [a] ;a的值赋给ecx寄存器
004018F9 add ecx,2 ;a+2
004018FC mov byte ptr [a],cl ;a=a+2,给a赋值,这是变量a就是4了,同理cl为ecx的低八位
004018FF movsx edx,byte ptr [a] ;a的值赋给edx寄存器,为4
00401903 push edx ;将edx的内容压栈
00401904 movsx eax,byte ptr [a]
;问题出在这句,本来在这句代码之前,eax的内容为2,
;即第一个算式a*=2的内容;这里重新赋值,导致eax变成了4,下图为单步执行时寄存器值的变化
00401908 push eax ;将eax的内容压栈
printf("%d %d", a += 2, a *= 2);
00401909 push offset string "%d %d" (0407B30h)
0040190E call _printf (040104Bh)
00401913 add esp,0Ch
至此,我们可以从汇编代码中可以看出“4 4”结果整个的计算过程
群里大佬的总结:(对应开始时输出两次变量a的值)
最后验证了一下,确实是从右到左算完后,再从左到右输出
(小弟俺第一次使用vs的反汇编动能,也没接触过cl的汇编程序,如有错误恳请纠正)