Help with post-increment and sequence points

L

laird

#include <iostream>
int main() {
int i = 1;
std::cout << i << i++ << i << "\n";
}

Compiling this code in g++ prints out 212 . Is this correct? If so, I don'tunderstand why.

Shouldn't this actually be equivalent to f(f(f(f(std::cout,i),i++),i),"\n")where f is operator<< ? In that case, each time a function is entered, there should be a sequence point which makes the side effects happen. So I'd expect the output to be 112 instead.

% g++ --version
g++ (Debian 4.6.1-4) 4.6.1

Best regards,
Laird Breyer
 
V

Victor Bazarov

#include<iostream>
int main() {
int i = 1;
std::cout<< i<< i++<< i<< "\n";

This expression actually means
std::cout.
operator<<(i). // #1
operator<<(i++). // #2
operator<<(i). // #3
operator<<("\n"); // #4

Which, in reality means

mem_op<<( // #4
mem_op<<( // #3
mem_op<<( // #2
mem_op<< ( std::cout, i), // #1
i++ ), i ), "\n");

which, according to the Standard can have any order of evaluation of its
operands, except that there is a sequence point before a call to a
function. So, before calling #4, it has to evaluate #3, which means it
will call the function, and in order to do that it has to call #2, and
in order to do that it has to call #1. BUT... The second operands in
all those calls can be evaluated an *any* time after the expression
starts evaluating just before the function call that needs it. IOW, the
*second* arguments could be evaluated as i,"\n",i,i++, and you would see
111, which should still be "correct". Or the order could be
"\n",i++,i,i, which *could* give 211, or 222, depending on when the
effects of ++ take place (they are supposed to take place before the
next "intervening" sequence point).
}

Compiling this code in g++ prints out 212 . Is this correct? If so, I don't understand why.

It is just as correct as any other combination of 1s and 2s.
Shouldn't this actually be equivalent to
f(f(f(f(std::cout,i),i++),i),"\n") where f is operator<< ? In that case,
each time a function is entered, there should be a sequence point which
makes the side effects happen. So I'd expect the output to be 112 instead.

Yes, but the sequence point has no effect on when the *second* argument
for every call is evaluated. You seem to forget that.
% g++ --version
g++ (Debian 4.6.1-4) 4.6.1

Best regards,
Laird Breyer

V
 
N

Nick Keighley

This expression actually means
     std::cout.
       operator<<(i).          // #1
         operator<<(i++).      // #2
           operator<<(i).      // #3
             operator<<("\n"); // #4

Which, in reality means

     mem_op<<(        // #4
       mem_op<<(      // #3
         mem_op<<(    // #2
           mem_op<< ( std::cout, i),  // #1
           i++ ), i ), "\n");

which, according to the Standard can have any order of evaluation of its
operands, except that there is a sequence point before a call to a
function.  So, before calling #4, it has to evaluate #3, which means it
will call the function, and in order to do that it has to call #2, and
in order to do that it has to call #1.  BUT...  The second operands in
all those calls can be evaluated an *any* time after the expression
starts evaluating just before the function call that needs it.  IOW, the
*second* arguments could be evaluated as i,"\n",i,i++, and you would see
111, which should still be "correct".  Or the order could be
"\n",i++,i,i, which *could* give 211, or 222, depending on when the
effects of ++ take place (they are supposed to take place before the
next "intervening" sequence point).



It is just as correct as any other combination of 1s and 2s.




f(f(f(f(std::cout,i),i++),i),"\n") where f is operator<< ? In that case,
each time a function is entered, there should be a sequence point which
makes the side effects happen. So I'd expect the output to be 112 instead..

Yes, but the sequence point has no effect on when the *second* argument
for every call is evaluated.  You seem to forget that.

with both i and i++ in there is taht undefined behaviour- or merely
implementaion defined behaviour?
 
V

Victor Bazarov

with both i and i++ in there is taht undefined behaviour- or merely
implementaion defined behaviour?

Well, since no requirement is set on the order in which the calls and
the evaluation of the "second arguments" is going to happen, it is
probably undefined. The "implementation-defined" carries the
requirement to be documented ([defns.impl.defined]), and the order of
evaluating of the arguments does not have to be documented.

V
 
M

Markus Wichmann

#include <iostream>
int main() {
int i = 1;
std::cout << i << i++ << i << "\n";
}

Compiling this code in g++ prints out 212 . Is this correct? If so, I don't understand why.

Shouldn't this actually be equivalent to
f(f(f(f(std::cout,i),i++),i),"\n") where f is operator<< ?
In that case, each time a function is entered, there should
be a sequence point which makes the side effects happen. So
I'd expect the output to be 112 instead.

This logic does not hold. You do call

f(f(std::cout, i), i++)

among other functions. However, the order in which the arguments to the
outer function are evaluated is unspecified. Thus you invoke undefined
behaviour. Which means the output could have been "undefined behaviour
detected!" or, indeed, anything.
% g++ --version
g++ (Debian 4.6.1-4) 4.6.1

Best regards,
Laird Breyer

HTH,
Markus
 
L

laird

f(f(f(f(std::cout,i),i++),i),"\n") where f is operator<< ? In that case,
each time a function is entered, there should be a sequence point which
makes the side effects happen. So I'd expect the output to be 112 instead.

Yes, but the sequence point has no effect on when the *second* argument
for every call is evaluated. You seem to forget that.

Victor, this explains why I was confused. I was secretly thinking of the other case

cout << "good " << "news " << "everybody\n";

where the compiler can also evaluate the strings in any order, but this works in that case because they are all constant, so every possible ordering gives the same return value.

Thanks to everybody who responded.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top