C中函数调用的后缀或前缀增量的未定义行为
我在这个网站上看到,函数调用中的前缀增量或后缀增量可能会导致未定义的行为。 我最近经历过其中一个。 源代码是这样的:
#include void call(int,int,int); int main() { int a=10; call(a,a++,++a); printf("****%d %d %d***_\n",a,a++,++a); return 0; } void call(int x,int y,int z) { printf("%d %d %d",x,y,z); }
输出结果为12 11 12 **** 14 13 14 *** _。 但是,当a在函数中首先打印时,它不应该是10吗? 它为什么变成12? 另外,为什么++从12减少到11? 有人可以请解释一下吗? 谢谢。
这是未定义的行为,因此完全取决于编译器的实现,其中以下操作的顺序如下:
- 提交参数
a
- 提交参数
a++
- 提交参数
++a
- 增加
a
for++a
- 为
a++
增加a
编译器唯一知道的是:2。必须在5之前发生,4。必须在3之前发生。
你在观察:
++a; submit argument 2 a++; submit the other arguments
您的示例代码需要我们考虑两件事:
未指定评估的函数参数顺序。 因此,首先评估
++a
或a++
但它依赖于实现。在修改之间没有序列点的情况下修改多次的值也是未定义的行为。
由于第2点,你在这里有两个未定义的行为(你做了两次)。 注意未定义的行为并不意味着没有任何反应; 这意味着一切都会发生。
call(a,a++,++a); /* UB 1 */ printf("****%d %d %d***_\n",a,a++,++a); /* UB 2 */
C和C ++标准不表示函数参数的评估顺序。 简而言之,编译器从右到左或从左到右计算参数并不是不正确的。
最好的答案是, 远离这种“未定义的行为”; 因为它可能导致微妙的可移植性问题。
没有要求等于任何东西 ; 这就是未定义行为的含义。 完全取决于编译器以其认为合适的任何顺序评估call
和printf
的参数,因为该语言没有指定需要评估的顺序。