我知道写点像
++a = a++;
不仅不可读,而且还违反了c / c ++序列点。
这些限制来自哪里?在将它们视为错误之前,如何才能看到这些“问题”?
答案 0 :(得分:9)
基本上每个语句之间都有一个C ++ 03序列点。有关更多信息,请参阅SO C++ FAQ。有关更多信息,请参阅C ++标准,并记住在C ++ 11标准中,序列点被替换为在之前排序,在关系之后排序。
为避免出现问题,请不要试图在每个表达式中做太多聪明。
不要尝试编译器的工作:将其留给编译器。你的工作是编写其他人很容易理解的代码,即清晰代码。多次更新和不必要地使用具有副作用的操作符与此不兼容。
提示:尽可能洒掉const
。
这限制了读者必须考虑的可能的状态变化。
答案 1 :(得分:8)
它们来自C或C ++标准,它有效地列出sequence points。 1 在一些简单的情况下,您的编译器可能会警告您正在调用未定义的行为,但不是一般情况。
但是,如果您正在撰写“有趣”的代码,例如您的示例,那么您通常只会违反序列点要求。语言标准可以对诸如此类的代码(这是Java所使用的语言)施加特定约束,但是没有很大的好处,以及阻止某些类型的优化的潜在缺点。
<小时/> <子> 1。 C ++ 11中的术语略有变化,但我认为原理基本相同。
答案 2 :(得分:5)
如何在发现错误之前看到这些“问题”?
以最严格的级别编译程序,并将所有警告的设置指定为错误。大多数主流编译器都会指出由于序列点而导致的未定义行为错误。
使用gcc,你可以使用:
-Wsequence-point
指出序列点问题。请注意,如果您使用-Wall
,则会默认启用它。
当然,最好的方法是尝试编写更易读的代码,以避免序列点错误冒险。
答案 3 :(得分:-1)
这些限制来自哪里?在发现它们为错误之前,如何看待那些“问题”?
它们来自执行过程中操作顺序的含糊不清(或自由修改)。
例如:
++a = a++;
对于左值的预增是在右值的后增之前还是之后,该语言未定义。在此处添加约束将导致大量成本;一般好处是什么?该示例代码“应”如何清晰,明显地表现出来?
为提高性能,编译器和/或处理器可以(严格限制)更改程序中的操作顺序。
过度限制执行顺序:
让我们看看如何限制不同代码示例的执行顺序:
a = b++ + ++c - --d - e--;
假设只有有限数量的寄存器可用,并且某些变量(“ d”和“ e”)在寄存器中,而有些则没有。严格限制执行顺序(从左到右)可能需要:
例如,如果允许首先处理'd'和'e'并在稍晚的时间增加'b',编译器也许能够显着减少步骤数并提高性能。