rikimaru2013 Asked:2020-01-20 05:38:32 +0000 UTC2020-01-20 05:38:32 +0000 UTC 2020-01-20 05:38:32 +0000 UTC 此代码是否包含 UB? 772 此代码是否包含 UB? int i = 6; i = 7, ++i, i++; c++ 3 个回答 Voted AnT stands with Russia 2020-01-20T05:57:02Z2020-01-20T05:57:02Z 不,这里没有 UB,因为这个表达式中运算符和操作数的分组如下 (i = 7), (++i), (i++); 逗号运算符对其操作数的值的评估及其副作用的执行进行排序。(在旧术语中,“逗号”运算符是一个序列点)。 首先评估左操作数,然后评估右操作数。此外,计算左操作数的所有副作用甚至会在右操作数开始计算之前发生。 5.19 逗号运算符[expr.comma] 1 [...] 从左到右评估一对由逗号分隔的表达式;左边的表达式是丢弃值表达式。与左表达式关联的每个值计算和副作用在与右表达式关联的每个值计算和副作用之前排序。[...] Best Answer Vlad from Moscow 2020-01-20T06:23:40Z2020-01-20T06:23:40Z 逗号运算符、逻辑与运算符 (&&)和逻辑或运算符 (||)等运算符会在计算下一个操作数之前执行与第一个操作数的表达式关联的任何副作用。 例如,你可以写 std::cout << ( i++, i++, i++ ) << std::endl; 或者 if ( i++ > 0 && i++ < 10 ) { /* ... */ } 或者 if ( i++ == 0 || i++ % 3 == 0 ) { /* ... */ } 这同样适用于 C++ 中的初始化列表。例如, int a[] = { i++, ++i }; 或者在类构造函数中 struct A { int x; int y; A( int i ) : x( i++ ), y( ++i ) { //,,, } }; 虽然这些运算符在副作用方面的行为在 C++ 和 C 中是相同的,但两种语言在初始化列表方面存在重要差异。在 C 中,评估初始化列表中初始化器的副作用的顺序是未定义的。 来自 C 标准(6.7.9 初始化) 23 初始化列表表达式的求值相对于彼此的顺序是不确定的,因此任何副作用发生的顺序都是未指定的。152 将此引用与 C++ 标准(8.5.4 列表初始化)中的引用进行比较 4 在花括号初始化列表的初始化列表中,初始化子句,包括包扩展 (14.5.3) 产生的任何结果,按它们出现的顺序进行评估。也就是说,在初始化列表的逗号分隔列表中,与给定初始化器子句关联的每个值计算和副作用都在与它后面的任何初始化器子句关联的每个值计算和副作用之前排序。[注意:无论初始化的语义如何,此评估顺序均成立;例如,当初始化列表的元素被解释为构造函数调用的参数时,它适用,即使通常对调用的参数没有顺序约束。--尾注] avp 2020-01-20T05:56:59Z2020-01-20T05:56:59Z 为什么会这样? 该操作,唯一确定表达式评估的顺序(从左到右),结果将是最后一个表达式的值。 你i会有9个。
不,这里没有 UB,因为这个表达式中运算符和操作数的分组如下
逗号运算符对其操作数的值的评估及其副作用的执行进行排序。(在旧术语中,“逗号”运算符是一个序列点)。
首先评估左操作数,然后评估右操作数。此外,计算左操作数的所有副作用甚至会在右操作数开始计算之前发生。
逗号运算符、逻辑与运算符 (&&)和逻辑或运算符 (||)等运算符会在计算下一个操作数之前执行与第一个操作数的表达式关联的任何副作用。
例如,你可以写
或者
或者
这同样适用于 C++ 中的初始化列表。例如,
或者在类构造函数中
虽然这些运算符在副作用方面的行为在 C++ 和 C 中是相同的,但两种语言在初始化列表方面存在重要差异。在 C 中,评估初始化列表中初始化器的副作用的顺序是未定义的。
来自 C 标准(6.7.9 初始化)
将此引用与 C++ 标准(8.5.4 列表初始化)中的引用进行比较
为什么会这样?
该操作
,唯一确定表达式评估的顺序(从左到右),结果将是最后一个表达式的值。你
i会有9个。