C++ evaluation order

《C++Primer5th》中文版第124页
C++语言没有明确规定大多数二元运算符的求值顺序,
给编译器优化留下了余地。
这种策略实际上是在代码生成效率和程序潜在缺陷之间进行了权衡,这个是否可以接受?

1. First of all, it can be known that the priority specifies the combination of the operands, but it does not specify the order in which the operands are evaluated.

for example:

int i=f1()*f2();

Here, although f1 and f2 are called before the multiplication, it is not known whether f1 is called first or f2 is called first.
2. Another example is the associative law:
--

int i=0;
cout<<i<<" "<<+i<<endl;

The result may be 0 1 or 1 1.
Because although << is left associative, for those operators that do not explicitly specify the evaluation order of the operands, the evaluation order has nothing to do with precedence and associativity.
So the above expression is undefined, that is, if the expression points to and modifies the same object, such behavior is undefined

  • Logical AND &&
  • Logical NOT||
  • condition? :
    -Comma, the
    above four operators clearly specify the evaluation order of the operands.

3. C++ Manual

The order of evaluation of almost all C++ operators (including the order of evaluation of function arguments in function call expressions and the order of evaluation of subexpressions in any expression ) is unspecified. The compiler can evaluate in any order , and can choose another order when evaluating the same expression again. Example: The expression f1() + f2() + f3() is (f1() + f2()) + f3() due to left-to-right associativity analysis of operator+, but a function call to f3 at runtime may first , last, or between f1() and f2(). 4. Sequence point rules (the following content is from the C++ manual ) -- Sequence point rules (before C++11) define that evaluation may have side effects: that is, accessing the object referred to by the volatile lvalue, modifying the object, calling the library I/ O function or call a function that does any of these actions.







A sequence point is the point in the execution sequence at which all side effects from previous evaluations in the sequence have completed and none of the side effects of subsequent evaluations have started.

Rule
1) Every complete expression ends (typically at a semicolon) with a sequence point.

2) When a function is called (whether the function is inlined or not, and whether the function call syntax is used or not), there is a sequence point after the evaluation of all function arguments (if any) that occurs before any expressions or statements in the function body are executed .

3) There is a sequence point after the return value of the function is copied, and before the execution of any statement outside the function.

4) Once function execution begins, expressions from the caller function are not evaluated (functions cannot be interleaved) until the called function completes.

5) In the evaluation of each of the following four expressions using built-in (non-overloaded) operators, there is a sequence point after the evaluation of expression a.

a && b
a || b
a ? b : c
a , b

undefined behavior

  • 1) The stored value of a scalar object can be modified at most once between sequence points before and after, otherwise the behavior is undefined.

    i = ++i + i++; // 未定义行为
    i = i++ + 1; // 未定义行为( C++17 前)
    i = ++i + 1; // 未定义行为( C++11 前)
    ++ ++i; // 未定义行为( C++11 前)
    f(++i, ++i); // 未定义行为( C++17 前)
    f(i = -1, i = -1); // 未定义行为( C++17 前)
  • 2) Between before and after sequence points, access to the previous value of the scalar object modified by the evaluation of the expression must only be used to determine the value to be stored. If accessed in any other way, the behavior is undefined.

cout << i << i++; // 未定义行为( C++17 前)
a[i] = i++; // 未定义行为( C++17 前)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325301597&siteId=291194637