语句'int val =(++ i> ++ j)吗?++ i:++ j;`调用未定义的行为?

max*_*001 24 c ternary-operator sequence-points

给定以下程序:

#include <stdio.h>
int main(void)
{
    int i = 1, j = 2;
    int val = (++i > ++j) ? ++i : ++j;
    printf("%d\n", val); // prints 4
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

的初始化val似乎可能隐藏了一些未定义的行为,但是我看不到对象被多次修改或在其间没有序列点的情况下被修改和使用的任何地方。有人可以对此进行纠正或证实吗?

dbu*_*ush 37

这段代码的行为已明确定义。

确保条件表达式中的第一个表达式先于第二个表达式或第三个表达式被求值,并且仅第二个或第三个表达式中的一个将被求值。C标准的 6.5.15p4节对此进行了描述:

第一个操作数被求值;在它的评估与第二个或第三个操作数的评估(无论哪个被评估)之间都有一个序列点。仅当第一个操作数不等于0时,才对第二个操作数求值;仅当第一个操作数等于0时,才计算第三个操作数;结果是第二个或第三个操作数的值(以所评估的为准),转换为以下所述的类型。

对于您的表情:

int val = (++i > ++j) ? ++i : ++j;
Run Code Online (Sandbox Code Playgroud)

++i > ++j首先评估。的递增值ij在比较中使用的,所以它成为2 > 3。结果为假,因此将++j评估结果为假++i。因此,(再次)递增的值j(即4)然后分配给val

  • 感谢您的详细而直接的答复! (3认同)

ali*_*oar 9

为时已晚,但可能有用。

(++i > ++j) ? ++i : ++j;
Run Code Online (Sandbox Code Playgroud)

在文档中,ISO/IEC 9899:201xAnnex C(informative)Sequence points我们发现有一个序列点

在条件?:运算符的第一个操作数的求值与第二个和第三个操作数中的任一个的求值之间

为了获得良好定义的行为,一个对象不得在2个序列点之间修改2次(通过副作用)同一对象。

在您的表达中,唯一可能出现的冲突将出现在第一个和第二个++i或之间++j

在每个序列点,最后存储在对象中的值应与抽象机规定的值一致(这是您在纸上(如在图灵机上)要计算的值)。

引用来自 5.1.2.3p3 Program execution

在表达式A和B的求值之间存在序列点意味着,与A关联的每个值计算和副作用都要在与B关联的每个值计算和副作用之前进行排序。

当您的代码中有副作用时,它们将按不同的表达式排序。该规则说,您可以根据需要在2个序列点之间置换这些表达式。

例如。i = i++。由于此表达式中涉及的所有运算符都不表示序列点,因此您可以根据需要置换副作用的表达式。C语言允许您使用任何这些序列

i = i; i = i+1;i = i+1; i=i;tmp=i; i = i+1 ; i = tmp;tmp=i; i = tmp; i = i+1;提供与计算抽象语义相同的结果的任何内容都要求对此计算进行解释。ISO9899标准将C语言定义为抽象语义。


Dou*_*rie 5

您的程序中可能没有UB,但存在以下问题:语句是否int val = (++i > ++j) ? ++i : ++j;调用未定义的行为?

答案是肯定的。由于ij签名,两个或两个增量操作都可能溢出,在这种情况下,所有投注均关闭。

当然,在您的完整示例中不会发生这种情况,因为您已将值指定为小整数。

  • 我向您保证,问题不在于有符号整数溢出。关于三元运算符的第一个操作数与从第二个和第三个操作数获胜的那个之间是否存在序列点。 (4认同)
  • 这个问题是关于“一些未定义的行为”的,有关具体实现的数据类型的提示完全适合于这样一个公开的问题。有符号整数Flow是UB。 (2认同)