重复使用前缀 ++ 运算符时的未定义行为

Undefined behaviour in repeated use of prefix ++ operator

本文关键字:未定义 运算符 前缀      更新时间:2023-10-16

我读到了这个关于未定义行为的答案,我看到了以下陈述:

++++++i;     // UB, parsed as (++(++(++i)))

我不认为这是未定义的行为。我有一个疑问,它真的是C++中的UB?如果是,那么如何?

另外,我使用g++ prog.cpp -Wall -Wextra -std=gnu++1z -pedantic命令制作了程序并进行编译,它工作正常,没有任何警告。它给出了预期的输出。

#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout<<++++++i<<endl;
}

在 C++03 中,它是未定义的行为。在C++11中不是。各种预递增之间没有序列点。如果i是用户定义的类型,它将是定义良好的行为,因为这样就会有一个函数调用(序列点)。

在C++11 中,序列点的概念被之前/之后的序列所取代。缺陷 637 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637) 提供了一个以前未定义的构造变得明确定义 (i = ++i + 1) 的示例。

为了理解为什么它不是未定义的行为,让我们看看我们需要的部分。++i等效于i = i + 1(除了i只计算一次)。此外,如果我们用inc代替i = i + 1++(i = i + 1)变得inc = inc + 1

[expr.ass] 指出:

在所有情况下,赋值都是在左右操作数的值计算之后以及赋值表达式的值计算之前排序的。

因此,i = i + 1中的赋值是在inc的值计算之前排序的;然而,inc = inc + 1中的赋值是在inc的值计算之后排序的。没有未定义的行为,因为分配是按顺序排列的。

有时行为是未定义的,即使很难想象它是如何被错误处理的。但是在C++11之前,这是未定义的,因为同一对象被多次修改而没有指向干预序列。

可以想象一个编译器,它通过合并所有修改来"优化"代码i.因此,每个增量都会递增原始值。但这不是重点。如果标准这么说,UB 就是 UB。我们是否能想象它是如何失败的并不重要。