这是C++中未定义的行为吗

Is this undefined behaviour in C++?

本文关键字:未定义 C++ 这是      更新时间:2023-10-16

我想知道下面最后一个if中对x的访问是否是未定义的行为:

int f(int *x)
{
    *x = 1;
    return 1;
}
int x = 0;
if (f(&x) && x == 1) {
    // something
}

这不是未定义的行为,因为运算符&&是序列点

它定义得很好。

参考-C++03标准:

第5节:表达式,第4段:

除非注意到[例如用于&&和||]的特殊规则,否则单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序为未指定

在中时,

第1.9.18节

在以下表达式的评估中

a && b
a || b
a ? b : c
a , b

使用这些表达式中运算符的内置含义,在第一个表达式的求值之后有一个序列点(12)。

已定义。C/C++执行惰性求值,并定义首先计算和检查左表达式。如果它是真的,那么正确的将是。

否,因为&&定义了一个排序,其中lhs必须在rhs之前计算。

||?:,上也有一个定义的顺序。其他操作数上没有。

可比:

int x = 0;
if (f(&x) & x == 1) {
    // something
}

那么它是未定义的。在这里,lhs和rhs都将按任意顺序进行计算。这种非快捷形式的逻辑和不太常见,因为快捷通常被视为至少对性能有益,并且通常对正确性至关重要。

这不是未定义的行为。原因取决于两个事实,这两个都足以给出定义的行为

  • 函数调用和终止是一个序列点
  • '&'运算符是一个序列点

以下是定义的行为太

int f(int *x) {
    *x = 1;
    return 1;
}
int x = 0;
if (f(&x) & (x == 1)) {
    // something
}

但是,您不知道x == 1的计算结果是true还是false,因为可以先计算&的第一个或第二个操作数。不过,这对于定义此代码的行为并不重要。

它没有定义,但也不应该编译,因为您正试图将指向x(&x)的指针分配给引用。

&&将从左到右进行评估(如果左侧评估为false,则评估将停止)。

编辑:修改后,它应该编译,但仍将被定义(因为如果使用指针或引用,这并不重要)。

它将把调用程序块中局部变量x的地址作为参数传递给f(指向int的指针)。然后,f将参数(堆栈上的一个临时变量)设置为地址1(这不会造成问题)并返回1。由于1为true,if()将继续计算x==1,这是false,因为主块中的x仍然为0。

if块的主体将不会执行。

编辑

对于问题的新版本,将执行正文,因为在f()返回后,调用块中的x为1。