是"返回i ++,i,i ++;" C中的未定义行为?

msc*_*msc -2 c undefined-behavior language-lawyer c11

如果我这样写:

i = i++, i, i++;
Run Code Online (Sandbox Code Playgroud)

它是C语言中未定义的行为.

但是,如果我这样写:

return i++, i, i++; // Is it UB?
Run Code Online (Sandbox Code Playgroud)

是不确定的行为?

例:

#include <stdio.h>

int f(int i)
{
    return i++, i, i++; // Is it UB?
}
int main() {
    int i = 1;
    i = i++, i, i++;

    i = f(i);
    printf("%d\n",i);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 12

i = i++, i, i++;是UB,因为它=具有更高的优先级,,因此表达式被解析为(i = i++), i, i++子表达式i = i++调用UB的位置1).

即使代码已经被写成i = (i++, i, i++);它会仍然一直UB,因为现在之间没有顺序点最右边的i++i,左操作数= 1) .

但是,当您删除该i =部件时,您将删除该不明确的行为.return i++, i, i++; 必须按顺序排序为:

i++, the left one
sequence point from left comma
i
sequence point from right comma
i++, the right one
sequence point before returning
Run Code Online (Sandbox Code Playgroud)

所以它定义明确.


资料来源:

1) C11 6.5/2

如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义.如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的.

然后还是C11 6.5.16/3

在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序.对操作数的评估是不确定的.

值得注意的是,关于赋值的上述文本在C11和C++ 11之间是不同的.

  • 但代码非常糟糕.根据经验,任何将"++"与同一表达式中的其他操作混合的代码都是可疑的.很少有理由将"++"与其他操作混合在一起,在99%的情况下它只是草率,危险的风格. (4认同)

Oli*_*rth 8

return i++, i, i++;
Run Code Online (Sandbox Code Playgroud)

不,它不是未定义的行为,因为逗号运算符定义了一个将修改访问分隔开的序列点i.

因此,此代码相当于:

i++;        // The left-most subexpression
i;
return i++; // The right-most subexpression
Run Code Online (Sandbox Code Playgroud)

为了比较:

i = i++, i, i++;
Run Code Online (Sandbox Code Playgroud)

未定义的行为,因为它的,优先级低于=,因此它相当于:

(i = i++), i, i++;
Run Code Online (Sandbox Code Playgroud)

并且i = i++是未定义的行为(有关此特定情况的更多信息,请参阅问题).