Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected order of evaluation (compiler bug?) [duplicate]

Possible Duplicate:
Undefined Behavior and Sequence Points

I'm not sure if this is a gcc bug or not, so I'll ask:

unsigned int n = 0;
std::cout << n++ << n << ++n;

gcc gives the extremely strange result: "122" which AFAICT is impossible. Because << is left associative, it should be the same as:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

and because there is a sequence point before and after evaluating arguments, n is never modified twice (or even accessed) between two sequence points -- so it shouldn't be undefined behaviour, just the order of evaluation unspecified.

So AFAICT valid results would be: 111 012 002 101

and nothing else

like image 498
user647445 Avatar asked Mar 07 '11 00:03

user647445


People also ask

In which order do the following will get evaluated by the C compiler?

The compiler will evaluate them in any order. It may choose another order when the same expression is evaluated again, but this will not affect the evaluated answer.

What are sequence points in C++?

Pre-C++11 Definitions A sequence point is a point in the execution sequence where all side effects from the previous evaluations in the sequence are complete, and no side effects of the subsequent evaluations started.


2 Answers

There is a sequence point between evaluating arguments and calling a function. There is no sequence point between evaluating different arguments.

Let's look at the outermost function call:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

The arguments are

  • operator<<(operator<<(std::cout, n++), n)

and

  • ++n

It is unspecified which of these is evaluated first. It's also allowed that the first argument is partially evaluated when the second argument is evaluated.

From the standard, section [intro.execution] (wording from draft 3225):

  • If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. — end note ]

  • Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. — end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

Because you have multiple operations with side effects on the same scalar object which are unsequenced with respect to each other, you're in that realm of undefined behavior, and even 999 would be a permissible output.

like image 66
Ben Voigt Avatar answered Oct 05 '22 05:10

Ben Voigt


The first rule of compiler bugs: it's probably not a compiler bug but a misunderstanding on your part. Using the postfix and prefix operators in the same statement results in undefined behavior. Try using the -Wall option to give you more warnings and show you the potential pitfalls in your code.

Let's see what GCC 4.2.1 tells us when we ask for warnings about test.cpp:

#include <iostream>

int main() {
    unsigned int n = 0;
    std::cout << n++ << n << ++n << std::endl;
    return 0;
}

When we compile:

$ g++ -Wall test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:5: warning: operation on ‘n’ may be undefined
like image 44
Seth Johnson Avatar answered Oct 05 '22 07:10

Seth Johnson