Sequence Points: A Deep Dive into the Inner Workings of C and C++.
Navigating a maze is like writing a C or C++ program: if you don't understand sequence points, you're likely to get lost.

Sequence Points: A Deep Dive into the Inner Workings of C and C++.

In this article, we will discuss what are sequence points in C and C++ programming languages, and why they are important for writing correct and predictable code, but firstly it's preferred to review this article:

Difference between precedence, associativity and order of evaluation.

Now, let's start with a brief introduction.

What are sequence points?

---------------------

Sequence points are points in the execution of a program where the order of evaluation of subexpressions and the modification of variables are well-defined. They help us avoid undefined or unspecified behavior that can arise from expressions that have side effects or depend on the history of evaluation.


What are side effects?

---------------------

A side effect is any change in the state of the program that is caused by the evaluation of an expression. For example, assigning a value to a variable, modifying an object, printing something to the screen, or calling a function that has side effects are all examples of side effects. Side effects are not inherently bad, but they can make the code more complex and harder to reason about, especially when they interact with each other or depend on the order of evaluation.


What is the order of evaluation?

--------------------------------

The order of evaluation is the order in which the subexpressions of an expression are evaluated, and their side effects are applied. For example, in the expression a + b * c, the subexpressions are a, b, c, b * c, and a + b * c. The order of evaluation determines which subexpression is evaluated first, second, third, etc., and when their side effects take place.

The order of evaluation can be either:

  • Sequenced: one subexpression is evaluated before another, and their side effects do not overlap.
  • Indeterminately sequenced: one subexpression is evaluated before another, but the order is unspecified by the language standard.
  • Unsequenced: two or more subexpressions are evaluated in an unspecified order, and their side effects may overlap.

The order of evaluation can affect the result and the behavior of an expression, especially when it involves side effects or variables that are modified more than once. For example, consider the following expressions:

  • f() + g(): The functions f() and g() may have side effects, such as printing something or changing global variables. The order of evaluation determines which function is called first, and which side effect happens first. However, the + operator does not introduce a sequence point, so the order of evaluation is indeterminately sequenced. This means that different compilers or platforms may choose different orders, and the result may vary.
  • i = i++: The variable i is modified twice in the same expression, once by the assignment operator and once by the increment operator. The order of evaluation determines whether the old value or the new value of i is assigned to i. However, there is no sequence point between the two modifications, so the order of evaluation is unsequenced. This means that the two modifications may happen in any order, or even simultaneously, and the result is undefined.


What are sequence points?

-------------------------

A sequence point is a point in the execution of a program where all side effects of previous evaluations are guaranteed to be completed, and no side effects of subsequent evaluations have started. A sequence point defines a clear boundary between two evaluations, where the order of evaluation is sequenced and well-defined.

Sequence points are important for avoiding undefined or unspecified behavior that can arise from expressions that have side effects or depend on the history of evaluation. By introducing sequence points, we can ensure that our code behaves predictably and consistently across different compilers and platforms.

The C and C++ standards define several sequence points in various contexts, such as:

  • The end of a full expression, such as a statement terminated by a semicolon, a return statement, or a function call argument.
  • The end of the first operand of certain operators, such as logical AND (&&), logical OR (||), conditional (?:), or comma (,).
  • The end of each initializer clause in an array or struct initializer.
  • The end of each declaration in a declaration statement.
  • The end of each conversion associated with an input/output format specifier.

For a complete list of sequence points in C and C++, please refer to [this article] (https://en.wikipedia.org/wiki/Sequence_point ).


Examples of sequence points

---------------------------

To illustrate how sequence points affect the order of evaluation and the behavior of expressions, let us look at some examples:

  • f() && g(): The logical AND operator (&&) introduces a sequence point between its operands. This means that f() is evaluated first, and its side effects are completed before g() is evaluated. Moreover, if f() returns false, then g() is not evaluated at all (short-circuiting).
  • (f(), g()): The comma operator (,) introduces a sequence point between its operands. This means that f() is evaluated first, and its side effects are completed before g() is evaluated. However, unlike the logical AND operator, the comma operator always evaluates both operands, regardless of their values.
  • i = ++i + 1: The prefix increment operator (++) introduces a sequence point between its operand and the result. This means that i is incremented first, and its side effects are completed before the addition is performed. The result is well-defined and equal to i + 2.
  • i = i++ + 1: The postfix increment operator (++) does not introduce a sequence point between its operand and the result. This means that i is modified twice in the same expression, without a sequence point between them. The order of evaluation is unsequenced, and the result is undefined.


Conclusion

----------

Sequence points are points in the execution of a program where the order of evaluation of subexpressions and the modification of variables are well-defined. They help us avoid undefined or unspecified behavior that can arise from expressions that have side effects or depend on the history of evaluation. By introducing sequence points, we can ensure that our code behaves predictably and consistently across different compilers and platforms.


Resources

----------

  1. stackoverflow .
  2. geeksforgeeks .
  3. wikipedia .




Andrew Byers

Software Developer

2 个月

Nice article, but I just wanted to point out one thing: function call arguments do not have a guaranteed order of evaluation (like other expressions separated by the comma operator). The order in which function arguments are evaluated is unspecified in both C and C++, at least in all the standards I am familiar with.

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了