c - : c = (b=a+2) - (a=1) ; 的未定义行为

标签 c expression undefined-behavior

我在书中读到了这个C programming : A modern approach -

According to C standard statements such as

 c = (b=a+2) - (a=1) ;

causes undefined behavior.

但是没有提及原因。我的理解是这样的:

  1. 所有变量在序列点之间仅被修改一次。 (所以不应该是UB)

  2. 子表达式的求值顺序未定义。 (但这并不意味着它会调用未定义的行为,对吧?)

还有什么原因导致它成为未定义的行为?

最佳答案

1 和 2 完全正确。对于操作数的计算顺序,C 中的大多数运算符都未指定。这意味着 (b=a+2)(a=1) 都可以首先进行评估,并且您无法知道哪个顺序适用于任何给定情况。

此外,如果在两个序列点之间修改变量,则不允许对该变量进行任何其他访问,除了计算要存储在其中的值之外。

C99 在 6.5 中声明了这一点(强调我的):

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.

因此,像 a = a+1 这样的代码是完全定义良好的,而像 a = a++ 这样的代码会导致未定义的行为。

这一切都归结为“抽象机器”,它是决定程序执行顺序的规则。将值写入变量会产生副作用,并且 C 标准规定所有副作用必须在下一个序列点之前发生。现在,如果您有多个与同一变量相关的副作用,则无法保证它们将按照彼此相关的顺序进行排序,直到到达下一个序列点。

避免由排序和求值顺序引起的错误的实用建议是保持表达式简单,每行使用尽可能少的运算符和尽可能少的副作用。对于您的原始示例,编写代码的更好方法是:

b = a + 2;
a = 1;
c = b - a;

编译器和人类读者都不会误解上述代码。


仅供记录,C11 有不同的文本,但含义完全相同:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

关于c - : c = (b=a+2) - (a=1) ; 的未定义行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25197937/

相关文章:

c - 与弦作斗争。我的功能出了什么问题?

rust - Rust 如何知道在堆栈展开期间是否运行析构函数?

c++ - 如何处理 clang 的 (3.9) -Wexpansion-to-defined 警告?

c - xcode 体系结构 x86_64 : "_err_quit", 的 undefined symbol 引用自:

c - 这段代码如何导致内存对齐的未定义行为?

c - 如何在没有 vector/递归的情况下为类似斐波那契的序列编写 C 程序?

linux - 在 Unix 中使用正则表达式连接两个文件(最好使用 perl)

.net - 需要帮助解决 LINQ 中 And 运算符的谓词错误

c - 将 int 截断为 char - 它是否已定义?

c# - LambdaExpression 为覆盖的属性获取不正确的 DeclaringType