c++ 这段代码是否有未定义的行为,是或否,为什么?

vxf3dgd4  于 2023-03-09  发布在  其他
关注(0)|答案(2)|浏览(126)
int a = 0;
cout<<(a++, ++a, a++, ++a, a++)<<"\n";

我怀疑上面的代码不是未定义的行为,我想验证一下。
我知道下面的代码有UB:

int a = 0;
cout << a++ << " " << ++a << " " << a++ << "\n";
xriantvc

xriantvc1#

第一个示例没有未定义的行为,因为它使用了内置逗号运算符。内置逗号运算符保证左操作数在右操作数之前 * 排序。这意味着左操作数的所有值计算和副作用都在右操作数的所有值计算和副作用之前发生。例如,由第一X1 M2 N1 X执行的从X1 M0 N1 X的读取和向X1 M1 N1 X的写入都发生在由第一X1 M5 N1 X执行的从X1 M3 N1 X的读取和向X1 M4 N1 X的写入之前,依此类推。
第二个例子在C17和更高版本中有明确定义的行为,因为在C17和更高版本中,可以保证在移位表达式E1 << E2中,表达式E1排在E2之前。注意,在这种情况下,<<操作符意味着调用重载的operator<<函数;然而,调用重载运算符函数的运算符的使用仍然具有与内置运算符相同的排序规则(参见此处;感谢HolyBlackCat指出了这一点)。
但是在C++17之前,第二个例子有未定义的行为,因为E1排在E2之前的规则不存在。为了理解表达式的行为,我们需要根据重载运算符函数的实际调用来写出它:

operator<<((operator<<(cout.operator<<(a++), " ")).operator<<(a++), " ").operator<<(a++);

这里没有用到逗号操作符,逗号只是用来分隔函数参数,并不调用内置的逗号操作符。
因为C17之前的C不保证表示要调用的函数的表达式在其参数之前求值,所以三个a++是无序的。这些无序的修改具有未定义的行为。

rsl1atfo

rsl1atfo2#

不,没有任何未定义的行为。如果我们使用第一个代码片段

int a = 0;
cout<<(a++, ++a, a++, ++a, a++)<<"\n";

在这里,在第一个a++中,将a的值递增到1,然后转到第二个参数++a。在第二个参数之后,值为2。在第三个参数之后,表示a++,值将变为3。然后转到第四个参数,首先将a的值递增到4,然后将a的值设置为4。在最后一个参数中有一个post increment and therefore first it will set the value of the a. That means set the value as 4. And after this line it will changes it's value to 5。如果你需要检查下面的代码。它会输出a的值为5。

#include <iostream>

int main() {
    int a = 0;
    std::cout << (a++, ++a, a++, ++a, a++) << "\n"; // 4
    std::cout << a << "\n"; // 5
    return 0;
}

在下一段代码中,它很简单,这里也没有任何未定义的行为。

int a = 0;
cout << a++ << " " << ++a << " " << a++ << "\n";

第一个a为0,然后在下一行设置并打印值a,然后递增1,因为是后递增,所以第一位的值为0,打印0后,它将由于后增量而增加1,并且在到达第二位之后,将遇到第一个++,并且必须在打印之前增加a值。这就是为什么1+1 =2,第二个位置将变为2。之后,直到转到第三个位置,没有任何增量。转到第三个位置后,有一个后增量,因为它将首先打印,然后增加其值。这就是为什么在最后一个位置也将打印为2。输出为0 2 2,这是正常输出。

相关问题