Help with post-increment and sequence points

Discussion in 'C++' started by laird@lbreyer.com, Oct 20, 2011.

  1. Guest

    #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
    , Oct 20, 2011
    #1
    1. Advertising

  2. Don't do that ....

    http://www2.research.att.com/~bs/bs_faq2.html#evaluation-order
    <http://www2.research.att.com/%7Ebs/bs_faq2.html#evaluation-order>

    bye.


    Il 20/10/2011 09:23, ha scritto:
    > #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.
    >
    > % g++ --version
    > g++ (Debian 4.6.1-4) 4.6.1
    >
    > Best regards,
    > Laird Breyer
    softwareEngineer, Oct 20, 2011
    #2
    1. Advertising

  3. On 10/20/2011 3:23 AM, wrote:
    > #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
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Oct 20, 2011
    #3
  4. On Oct 20, 1:26 pm, Victor Bazarov <> wrote:
    > On 10/20/2011 3:23 AM, wrote:
    >
    > > #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.


    with both i and i++ in there is taht undefined behaviour- or merely
    implementaion defined behaviour?
    Nick Keighley, Oct 20, 2011
    #4
  5. On 10/20/2011 9:06 AM, Nick Keighley wrote:
    > On Oct 20, 1:26 pm, Victor Bazarov<> wrote:
    >> On 10/20/2011 3:23 AM, wrote:
    >>
    >>> #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.

    >
    > 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
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Oct 20, 2011
    #5
  6. On 20.10.2011 09:23, wrote:
    > #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
    Markus Wichmann, Oct 20, 2011
    #6
  7. Guest

    On Thursday, 20 October 2011 23:26:33 UTC+11, Victor Bazarov wrote:
    > >
    > > 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.


    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.
    , Oct 20, 2011
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark Turney
    Replies:
    11
    Views:
    4,266
    dibeas
    Nov 13, 2006
  2. Replies:
    104
    Views:
    10,935
    Jordan Abel
    Oct 28, 2005
  3. jameskuyper
    Replies:
    1
    Views:
    405
    Tim Rentsch
    Apr 16, 2011
  4. Alf P. Steinbach /Usenet
    Replies:
    0
    Views:
    879
    Alf P. Steinbach /Usenet
    May 22, 2011
  5. Peng Yu

    post increment or pre increment?

    Peng Yu, Nov 21, 2008, in forum: Perl Misc
    Replies:
    7
    Views:
    508
    Peter J. Holzer
    Nov 23, 2008
Loading...

Share This Page