C++ 序列点从哪里来?

C++ 序列点从哪里来?,c++,c,sequence-points,C++,C,Sequence Points,我知道写这样的东西 ++a = a++; 不仅不可读,而且违反了c/c++序列点 这些限制来自哪里?在发现这些“问题”为bug之前,人们如何看待它们 在发现这些“问题”为bug之前,如何看待它们? 以最严格的级别编译程序,并启用所有警告的设置以指出错误。大多数主流编译器都会指出由于序列点而导致的未定义的行为错误 使用gcc,您可以使用: -Wsequence-point 应指出顺序点问题。请注意,如果使用-Wall,则默认情况下会启用它 当然,最好的办法是尝试编写更多的可读代码,避免序列点的

我知道写这样的东西

++a = a++;
不仅不可读,而且违反了c/c++序列点

这些限制来自哪里?在发现这些“问题”为bug之前,人们如何看待它们

在发现这些“问题”为bug之前,如何看待它们?

以最严格的级别编译程序,并启用所有警告的设置以指出错误。大多数主流编译器都会指出由于序列点而导致的未定义的行为错误

使用gcc,您可以使用:

-Wsequence-point
应指出顺序点问题。请注意,如果使用
-Wall
,则默认情况下会启用它


当然,最好的办法是尝试编写更多的可读代码,避免序列点的冒险。

< P>它们来自C或C++标准,有效地列出了1。在一些简单的情况下,编译器可以警告你调用未定义的行为,但一般情况下不可以。 然而,通常只有在编写“有趣”的代码(如示例)时才违反序列点要求。语言标准可能会对这样的代码施加特定的约束(Java等语言就是这样做的),但是没有太多的好处,也没有阻止某些类型的优化的潜在缺点



1.在C++11中,术语略有变化,但我认为其原理基本上仍然相同。

基本上,每个语句之间都有一个C++03序列点。有关更多信息,请参阅。对于更多的信息,请参考C++标准,并记住C++ 11标准中的序列点被替换为顺序之前和序列之后的关系。 为了避免问题,只是不要试图在每个表达式中做很多事情

不要试图做编译器的工作:让编译器来做。您的工作是编写其他人容易理解的代码,即清除代码。多次更新和不必要地使用具有副作用的运算符与此不兼容

提示:在任何可能的地方喷洒
const

这限制了读卡器必须考虑的可能状态更改

这些限制来自哪里?在发现这些“问题”为bug之前,人们如何看待它们

它们来自于执行过程中操作顺序的模糊性(或修改的自由度)

例如:

++a = a++;
该语言未定义左值的预增量是发生在右值的后增量之前还是之后。在这里增加一个约束将产生巨大的成本;一般的好处是什么?这个示例代码“应该”以什么清晰、明显的方式运行

为了提高性能,编译器和/或处理器可以(在严格限制范围内)更改程序中的操作顺序

过度限制执行顺序会:

  • 使针对不同目标体系结构实现C/C++变得更加困难
  • 增加语言规范的复杂性
  • 降低绩效(以换取什么收益?)
  • 防止许多编译时优化,降低性能
  • 需要在执行期间禁用流水线和硬件重新排序,再次降低性能
  • 可能会破坏现有的代码
让我们看一下约束不同代码示例的执行顺序:

a = b++ + ++c - --d - e--;
假设只有有限数量的寄存器可用,并且一些变量('d'和'e')在寄存器中,而一些不在寄存器中。严格约束执行顺序(从左到右)可能需要:

  • 从寄存器中丢弃“d”
  • 从寄存器中丢弃“e”
  • 加载“b”
  • 将其初始值保存为“b,原始”
  • 增量“b”(对于某些数据类型来说可能是非常重要的)
  • 存储修改的“b”
  • 重新加载“b,原件”
  • 加载“c”
  • 增量“c”
  • 保存更新的“c”
  • 添加“b,原始”+“c”,并另存为部分结果
  • 等等等等

如果允许先处理“d”和“e”,然后在稍晚的时间增加“b”,编译器可能会显著减少步骤数量并提高性能。

不过,这是语言设计限制还是机器(cpu)限制,任何语言通用?
错误:“a”上的操作可能未定义[-Werror=序列点]
-啊,谢谢,方便的编译器。打开所有警告,将警告编译并视为逻辑错误,您无需担心:
-Werror-Wall-Wextra-ansi-pedantic
@ArturMarianek:这是一个语言问题。该语言可以决定特定的求值顺序,编译器必须执行该顺序。这与硬件无关。@chris:
-Wall
默认启用它,正如我已经提到的。谢谢你的回答。我希望我能在这里“接受”许多答案;)使用时也会自动打开:-Wall谢谢您的回答。我希望我能在这里“接受”许多答案;)我刚才回答了一个关于C++98和C++11之间差异的问题:谢谢你的回答。我希望我能在这里“接受”许多答案;)代码是未定义的行为,意味着可能发生的任何事情。“无论[option 1]还是[option 2]发生都不是未定义的”。@M.M是的,我们和编译器都同意OP的代码示例将具有未定义的行为。然而OP提出的问题是,“如何才能在发现这些‘问题’之前将其视为bug?”我的目的是帮助读者理解为什么这是未定义的行为,为什么没有详细指定执行序列,因为这种理解导致能够看到执行可以重新排序的位置,以及发现此类iss的能力