void main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;//is this fine?
}
我最近开始阅读有关序列点的内容,但我无法弄清楚上面的代码示例是否正常。我知道&&
运算符引入了一个序列点,所以我不太确定表达式 z = x && y && ++z 的行为。有人请告诉我正确的答案。
void main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;//is this fine?
}
我最近开始阅读有关序列点的内容,但我无法弄清楚上面的代码示例是否正常。我知道&&
运算符引入了一个序列点,所以我不太确定表达式 z = x && y && ++z 的行为。有人请告诉我正确的答案。
在 C++ 03 中。
void main(void)
{
int x,y,z;
x=y=z=1; // Seq1 at ;
z = x && y && ++z;//is this fine? // Seq2 at ;
}
注意:请注意,运算符 && 有序列点,但在本示例中这些点不相关。
美好的!。一般来说,可能是也可能不是。取决于 x 和 y 的值。在您的具体情况下,这并不好。这段代码有可能有一些叫做未定义行为的东西。
如果对 z++ 求值(如在您的示例中,因为 x 和 y 为 1),则标量变量 'z' 在两个序列点 Seq1 和 Seq2 之间的表达式中被多次修改(见下文)。重要的是要注意赋值运算符不引入任何序列点。
$5/4-“除非另有说明,单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序是未指定的。53)在前一个和下一个序列点之间,一个标量对象应其存储的值最多可通过表达式的评估修改一次。此外,只能访问先验值以确定要存储的值。对于完整的子表达式的每个允许排序,应满足本段的要求表达式;否则行为未定义。”
在 C++0x 中
一旦我自己了解@litb 提到的讨论的细节,就会更新它。现在,我只是将其删除
然而,据我所知,在 C++0X 中,没有序列点的概念。这个表达式很好,不会调用未定义的行为。这是因为 ++ 对“z”的影响在赋值对“z”的副作用之前排序。
$1.9/15-“除非另有说明,对单个运算符的操作数和单个表达式的子表达式的求值是无序的。[注意:在程序执行期间多次求值的表达式中,对其进行无序和不确定排序的求值子表达式不需要在不同的评估中一致地执行。-结束注释]运算符的操作数的值计算在运算符结果的值计算之前排序。如果标量对象的副作用相对于另一个对象是无序的对同一标量对象或使用同一标量对象的值进行值计算的副作用,行为未定义。
$3.9/9 - “算术类型 (3.9.1)、枚举类型、指针类型、指向成员类型的指针 (3.9.2)、std::nullptr_t 和这些类型的 cv 限定版本 (3.9.3) 统称为标量类型。”
请注意,在表达式 'z = z++;' 其中 z 是一个标量变量,由于赋值运算符和后缀运算符 ++ 对“z”的副作用是未排序的(它们都没有在另一个之前排序)。
感谢@Prasoon 提供宝贵意见以从原始版本完善这篇文章
了解该行是否正常的一个简单方法是让编译器检查它。例如,gcc 有 一个-Wsequence-point
选项(由 启用-Wall
)来检查是否由于缺少序列点而存在未定义的行为。
你的程序
int main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;/*is this fine?*/
return 0;
}
产生此警告:
xc:在函数'main'中: xc:6:5: 警告:“z”上的操作可能未定义
是的,它会编译。
但是,如果您要询问逻辑错误:
1)&&
运算符引入了一个序列点,因为它可以在确定最终结果时终止表达式的评估(在这种情况下,一个0
值可以终止评估),因此它甚至不会到达该++z
部分 if x
or y
is零。
2)因为&&
运算符是逻辑运算符,所以结果将始终为 0 或 1,我怀疑这是否是您想要的。