5

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

Community
  • 1
  • 1
user647445
  • 1,287
  • 10
  • 10

3 Answers3

9

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.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thanks Ben, this seems to be the answer! I was under the impression there was a sequence point between evaluating different arguments, but there doesn't appear to be. Also thanks for the non condescending manner :) – user647445 Mar 07 '11 at 01:14
  • @user: Nope... the comma operator sequences its operands, but the comma used between function arguments is not the comma operator. – Ben Voigt Mar 07 '11 at 01:17
  • I would have expected that operations within an expression that includes a function call would be indeterminately sequenced with regard to that call, rather than unsequenced. Certainly if an expression contains two function calls they are indeterminately sequenced, rather than unsequenced, relative to each other. – supercat Mar 16 '16 at 16:45
  • @supercat: they are indeterminately sequenced wrt the function call, but unsequenced wrt each other. – Ben Voigt Mar 16 '16 at 16:55
  • @BenVoigt: I gotcha. You state that the first argument may be partially evaluated at the time the second argument is evaluated, but I think what you really mean is that the first argument may be partially evaluated when the *arguments* to the inner function call are evaluated. The function call itself--a key part of the argument evaluation--would be required to occur either entirely before or entirely after the first increment operation, would it not? – supercat Mar 16 '16 at 17:07
  • @supercat I think your mental model is correct even though your words aren't (the inner function call IS the first argument to the outer function) – Ben Voigt Mar 16 '16 at 17:12
  • @BenVoigt: The first function call is indeterminately sequenced with regard to the outer evaluation of n++ (vs. unsequenced), is it not? I think the problem is that the evaluation of the `++n` in the innermost function's argument is unsequenced relative to the evaluation of the `n++` in the outer argument. I think an `++n` within the called function itself would be indeterminately sequenced, but the `++n` isn't within a called function but occurs at some unspecified time before the function call. – supercat Mar 16 '16 at 18:17
  • @supercat: Yes, you've got it. – Ben Voigt Mar 16 '16 at 18:38
  • @BenVoigt: I thought so, but was suggesting that your language is perhaps unclear and you might want to clarify for any future readers that it is only the use of `n` *within the arguments* that invokes UB; if `n` were a global variable, the function could use it if it was prepared to handle the possibility that it could be called before or after the outer increment. – supercat Mar 16 '16 at 18:54
6

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
Seth Johnson
  • 14,762
  • 6
  • 59
  • 85
  • That rule has a few exceptions, for example when one is working with tools from a certain major Japanese electronics conglomerate. =P – Crashworks Mar 07 '11 at 00:55
  • In this case, it's not *undefined* behaviour, merely *unspecified*. This isn't the same as the standard `i = i + ++i` type questions... – Oliver Charlesworth Mar 07 '11 at 00:56
  • @Oli: Is the difference that "unspecified" will be reproducible given the same compiler and platform, whereas "undefined" may change from one program run to the next? Whatever the semantic difference, GCC reports it as "undefined," even though I agree that demons did not come flying out of my nose. – Seth Johnson Mar 07 '11 at 01:03
  • 1
    I agree that in practice, neither is a good thing to rely on. However, the standard appears to like make a song and dance about the distinction! I'm not sure why, though. – Oliver Charlesworth Mar 07 '11 at 01:05
  • 1
    @Oli: It *is* **undefined behavior**, according to draft n3225. – Ben Voigt Mar 07 '11 at 01:12
-3

Your code its an example of why in some books remark that experienced programmers don't like that(++,--) operator overload, even other languages (ruby) has not implemented ++ or --.

Gareve
  • 3,372
  • 2
  • 21
  • 23