Where do sequence points come from?

不打扰是莪最后的温柔 提交于 2019-11-29 10:01:05
Cheers and hth. - Alf

Basically there is a C++03 sequence point between each statement. For more information see the SO C++ FAQ. For even more information do consult the C++ standard, and keep in mind that in the C++11 standard sequence points were replaced with sequenced before and sequenced after relations.

To avoid problems, simply don't try to be too clever about doing a lot in each expression.

Don't try to do the compiler's job: leave that to the compiler. Your job is to write code that other humans can easily understand, i.e. clear code. Multiple updates and needless use of operators with side effects is not compatible with that.

Tip: sprinkle const just about everywhere possible.

That constrains the possible state changes that a reader must take into account.

They come from the C or C++ standard, which effectively lists sequence points.1 In a few simple cases, your compiler may be able to warn you that you're invoking undefined behaviour, but not in the general case.

However, you're generally only ever violating sequence-point requirements if you're writing "interesting" code such as your example. The language standard could impose particular constraints on code such as this (which is what languages such as Java do), but there's not a great deal of upside, and the potential downside of preventing certain types of optimisation.


1. The terminology has changed slightly in C++11, but the principle is still largely the same, I think.
Alok Save

How can one see those 'problems' before finding them as bugs?

Compile your program with strictest level and enable the settings for all warnings to be pointed out as errors. Most mainstream compilers do point out Undefined Behavior errors due to sequence points.

With gcc you can use:

-Wsequence-point

which shall point out sequence point problems. Note that it is enabled by default if you use -Wall.

Of course, the best way is to try and write more readable code which avoids sequence point mis-adventures.

Where do these limitations come from? How can one see those 'problems' before finding them as bugs?

They come from ambiguity in (or freedom to modify) the order of operations during execution.

For your example:

++a = a++;

the language leaves undefined whether the pre-increment on the lvalue should occur before or after the post-increment on the rvalue. Adding a constraint here would incur significant costs; what is the general benefit? What is the clear, obvious way that this example code 'should' behave?

To boost performance, the order of operations in a program may be changed (within strict limits) by the compiler and/or the processor.

Overly constraining execution order would:

  • Make it more difficult to implement C/C++ for different target architectures
  • Add complexity to the language specification
  • Cut performance (in return for what gain?)
  • Prevent many compile-time optimizations, cutting performance
  • Require disabling pipelining and hardware reordering during execution, again cutting performance
  • Perhaps break existing code

Let's look at constraining the order of execution for a different code sample:

a = b++ + ++c - --d - e--;

Suppose that only a limited number of registers are available, and that some of the variables ('d' and 'e') are in registers and some are not. Strictly constraining execution order (let's say left to right) might require:

  • Discard 'd' from registers
  • Discard 'e' from registers
  • Load 'b'
  • Save its initial value as 'b,original'
  • Increment 'b' (might be non-trivial for some data types)
  • Store modified 'b'
  • Reload 'b,original'
  • Load 'c'
  • Increment 'c'
  • Save updated 'c'
  • Add 'b,original' + 'c' and save as partial result
  • etc. etc.

While if allowed to e.g. process 'd' and 'e' first and to increment 'b' at a slightly later time, the compiler may be able to significantly reduce the number of steps and boost performance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!