为何C++中cout<<++i + ar[++i]与cout<<ar[++i]+ ++i输出不同?兼析未定义行为对自增运算的影响
为什么
arr[++i] + ++i和++i + arr[++i]会产生不同输出? 嘿,这个问题刚好戳中了C++里最容易让人困惑的**未定义行为(Undefined Behavior)**场景——当表达式中对同一个变量的多次修改没有明确的顺序约束时,编译器可以完全自由地选择求值顺序,甚至做出超出你预期的操作。
核心问题:未定义行为的根源
在C标准中,明确规定:如果一个表达式中对同一个对象的两次修改操作之间没有先序关系(C11及以后的说法,之前叫“序列点”),那么整个表达式的行为是未定义的。
具体到你的例子:
arr[++i] + ++i:加法的两个操作数(arr[++i]和++i)都修改了变量i,而且标准没有规定加法操作数的求值顺序(既可以先算左边,也可以先算右边,甚至可以以其他奇怪的方式求值)。++i + arr[++i]:同理,加法的两个操作数同样都修改了i,求值顺序依然是未被标准约束的。
这就导致编译器可以根据自己的实现、优化策略等任意处理这两个表达式,没有统一的结果。
针对你的两段代码分析
我们可以结合你看到的输出,反推编译器可能的求值顺序:
第一段代码输出3 2
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int i = 0; cout << arr[++i] + ++i << " " << i;
编译器可能选择了先计算左边的arr[++i],再计算右边的++i:
- 执行
++i,i变为1,取arr[1]的值为1; - 执行
++i,i变为2,这个操作数的值为2; - 相加
1 + 2 = 3,最后输出3和当前的i值2。
第二段代码输出4 2
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int i = 0; cout << ++i + arr[++i] << " " << i;
编译器这里可能选择了先执行两次++i,再计算数组取值和加法(这也是未定义行为允许的操作):
- 先执行第一个
++i(加法左边的),i变为1; - 再执行第二个
++i(数组下标里的),i变为2; - 取
arr[2]的值为2,然后相加2 + 2 = 4,最后输出4和当前的i值2。
当然,这只是一种可能的解释——换个编译器或者调整优化级别,结果完全可能不一样。
关键结论
- 这种包含对同一变量多次无顺序约束修改的表达式,属于未定义行为,标准不保证任何结果,甚至允许程序崩溃。
- 你看到的两个表达式输出不同,本质是编译器对未定义行为的处理方式不同,没有“为什么必须这样”的逻辑,完全是编译器的自由选择。
- 写代码时一定要避免这种写法,确保对变量的修改和读取操作有明确的顺序(比如用分号分隔成独立语句,或者使用中间变量)。
内容的提问来源于stack exchange,提问作者RaKo
相关产品推荐
相关产品推荐

