[cprg]$ cat test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int i=10;
printf("i=%d\ni++=%d\n++i=%d\n",i,i++,++i);
return 0;
}
[cprg]$ make
gcc -g -Wall -o test test.c
test.c: In function ‘main’:
test.c:7: warning: operation on ‘i’ may be undefined
test.c:7: warning: operation on ‘i’ may be undefined
[cprg]$ ./test
i=12
i++=11
++i=12
我不知道为什么会这件事发生。任何人都可以 我详细解释了这里发生了什么?
答案 0 :(得分:6)
C没有定义函数调用参数的评估顺序。你在那里遇到麻烦;)。
更新:
澄清定义的内容和不定义的内容:
函数指示符的评估顺序,实际参数和 实际参数中的子表达式未指定,但有一个序列点 在实际通话之前。
从ISO / IEC 9899:1999,第6.5.2.2节,函数调用
答案 1 :(得分:1)
这是main(我们需要的部分)的反汇编:
0x080483ed <+9>: movl $0xa,0x1c(%esp) # initializes i
0x080483f5 <+17>: addl $0x1,0x1c(%esp) # i += 1
0x080483fa <+22>: mov 0x1c(%esp),%edx # edx = i = 11
0x080483fe <+26>: addl $0x1,0x1c(%esp) # i += 1
0x08048403 <+31>: mov $0x80484f0,%eax # address of string
0x08048408 <+36>: mov 0x1c(%esp),%ecx # ecx = i = 12
0x0804840c <+40>: mov %ecx,0xc(%esp) # pushes ecx (++i)
0x08048410 <+44>: mov %edx,0x8(%esp) # and edx (i++)
0x08048414 <+48>: mov 0x1c(%esp),%edx # now gets edx (i)
0x08048418 <+52>: mov %edx,0x4(%esp) # and pushes it
0x0804841c <+56>: mov %eax,(%esp) # push address of string
0x0804841f <+59>: call 0x804831c <printf@plt> # write
现在,由于参数以相反的顺序被压入堆栈,反汇编显示第一个被推送的是ecx,所以我们可以假设它是++ i(因为它是printf中的最后一个参数),所以edx是i ++ 。奇怪的是,它决定先计算i ++,然后计算++ i。最后它加载i并推动它,但是,此时,我已经增加了两次,所以它是12。 这确实是未定义的行为!看:
printf("++i=%d\ni++=%d\ni=%d\n",++i,i++,i);
产生
++i=12
i++=10
i=12
答案 2 :(得分:0)
检查此StackOverflow链接以获取有关参数评估顺序的更多信息:
答案 3 :(得分:-2)
它与 C 上的i
,i++
和++i
表达式的评估顺序有关。例如没关系,但是如果你想避免奇怪的问题,在实际代码中不要依赖那个命令。