Can somebody explain to me the output of the following code?

Discussion in 'C Programming' started by asdfghjk, Aug 18, 2010.

  1. asdfghjk

    asdfghjk Guest

    #include <stdio.h>
    main()
    {
    struct Data
    {
    int a;
    int b;
    } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    struct Data *x = y;
    int i;
    for(i=0; i<4; i++)
    {
    x->a = x->b, ++x++->b;
    printf("%d %d\t", y.a, y.b);
    }
    }

    I have confusion regarding the ++x++->b part.
    The output is : 10 11 30 31 20 21 40 41
     
    asdfghjk, Aug 18, 2010
    #1
    1. Advertising

  2. asdfghjk

    Chris H Guest

    In message <
    s.com>, asdfghjk <> writes
    >#include <stdio.h>
    >main()
    >{
    > struct Data
    > {
    > int a;
    > int b;
    > } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    > struct Data *x = y;
    > int i;
    > for(i=0; i<4; i++)
    > {
    > x->a = x->b, ++x++->b;
    > printf("%d %d\t", y.a, y.b);
    > }
    >}
    >
    >I have confusion regarding the ++x++->b part.
    >The output is : 10 11 30 31 20 21 40 41


    See and click at the bottom to se the answers. It is a bit old now but
    it should answer your questions

    http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm

    --
    \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/
    \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
     
    Chris H, Aug 18, 2010
    #2
    1. Advertising

  3. asdfghjk

    Mark Bluemel Guest

    asdfghjk wrote:
    > #include <stdio.h>
    > main()
    > {
    > struct Data
    > {
    > int a;
    > int b;
    > } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    > struct Data *x = y;
    > int i;
    > for(i=0; i<4; i++)
    > {
    > x->a = x->b, ++x++->b;
    > printf("%d %d\t", y.a, y.b);
    > }
    > }
    >
    > I have confusion regarding the ++x++->b part.


    Not surprisingly, as I'm sure that was the originator's intention.

    Here's how I understand the line "x->a = x->b, ++x++->b;"

    We have two expressions separated by a "," (remember that an assignment
    is itself an expression). The expressions are evaluated left to right,
    and the rightmost is the value of the expression as a whole - which in
    this case (and probably most cases) we ignore.

    The first expression is "x->a = x->b" which is fairly self-explanatory.
    So the first time through the loop, the value 1 is replaced by the value 10.

    The second expression "++x++->b" does far too many things, IMHO. The
    pre-increment operates on the integer "x->b" (turning 10 to 11), while
    the post-increment operates on x, moving it on in step with the indexing
    in the loop. The value returned by the expression (which is again
    ignored) is the incremented value of "x->b".

    > The output is : 10 11 30 31 20 21 40 41
     
    Mark Bluemel, Aug 18, 2010
    #3
  4. asdfghjk

    Mark Bluemel Guest

    Chris H wrote:
    > In message <
    > s.com>, asdfghjk <> writes
    >> #include <stdio.h>
    >> main()
    >> {
    >> struct Data
    >> {
    >> int a;
    >> int b;
    >> } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    >> struct Data *x = y;
    >> int i;
    >> for(i=0; i<4; i++)
    >> {
    >> x->a = x->b, ++x++->b;
    >> printf("%d %d\t", y.a, y.b);
    >> }
    >> }
    >>
    >> I have confusion regarding the ++x++->b part.
    >> The output is : 10 11 30 31 20 21 40 41

    >
    > See and click at the bottom to se the answers. It is a bit old now but
    > it should answer your questions
    >
    > http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm
    >


    Hmmm... I'm not convinced

    That page claims that
    <Quote>
    uint16_t i = 10;
    uint16_t j = 0;

    j=2;
    printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );

    The code is effectively running the following calculation - "I=10, j=3,
    I * j++"

    </Quote>

    Firstly, I don't see why "uint16_t" is used in preference to plain
    "int", especially since "%d" in printf requires int...

    Secondly, I'm fairly sure that the explanation makes some major
    assumptions about the order of evaluation of function arguments, which
    aren't necessarily true.

    Am I mistaken?
     
    Mark Bluemel, Aug 18, 2010
    #4
  5. Chris H <> writes:

    > In message <
    > s.com>, asdfghjk <> writes
    >>#include <stdio.h>
    >>main()


    int main(void) is better. Given that main returns an int a return 0; is
    a good idea too.

    >>{
    >> struct Data
    >> {
    >> int a;
    >> int b;
    >> } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    >> struct Data *x = y;
    >> int i;
    >> for(i=0; i<4; i++)
    >> {
    >> x->a = x->b, ++x++->b;


    To the OP, a hint. It helps if you know how this is parsed. All
    postfix operators bind more tightly than all prefix operators so this is

    ++( (x++)->b )

    Does that help?

    >> printf("%d %d\t", y.a, y.b);
    >> }
    >>}
    >>
    >>I have confusion regarding the ++x++->b part.
    >>The output is : 10 11 30 31 20 21 40 41

    >
    > See and click at the bottom to se the answers. It is a bit old now but
    > it should answer your questions
    >
    > http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm


    I don't see the connection between that page and the OP's code. All
    your examples are undefined (though you never say that for some reason)
    but I think the OP's code is well-defined (though ghastly).

    --
    Ben.
     
    Ben Bacarisse, Aug 18, 2010
    #5
  6. Mark Bluemel <> writes:

    > Chris H wrote:
    >> In message <
    >> s.com>, asdfghjk <> writes
    >>> #include <stdio.h>
    >>> main()
    >>> {
    >>> struct Data
    >>> {
    >>> int a;
    >>> int b;
    >>> } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    >>> struct Data *x = y;
    >>> int i;
    >>> for(i=0; i<4; i++)
    >>> {
    >>> x->a = x->b, ++x++->b;
    >>> printf("%d %d\t", y.a, y.b);
    >>> }
    >>> }
    >>>
    >>> I have confusion regarding the ++x++->b part.
    >>> The output is : 10 11 30 31 20 21 40 41

    >>
    >> See and click at the bottom to se the answers. It is a bit old now but
    >> it should answer your questions
    >>
    >> http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm
    >>

    >
    > Hmmm... I'm not convinced
    >
    > That page claims that
    > <Quote>
    > uint16_t i = 10;
    > uint16_t j = 0;
    >
    > j=2;
    > printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >
    > The code is effectively running the following calculation - "I=10,
    > j=3, I * j++"
    >
    > </Quote>
    >
    > Firstly, I don't see why "uint16_t" is used in preference to plain
    > "int", especially since "%d" in printf requires int...


    That will be fine on many systems because uint16_t will promote to int
    when passed to printf but it does seem odd that, after including
    inttypes.h, the correct format was not used (PRIu16).

    As you say, for illustration, int would be much simpler.

    > Secondly, I'm fairly sure that the explanation makes some major
    > assumptions about the order of evaluation of function arguments, which
    > aren't necessarily true.
    >
    > Am I mistaken?


    I think all the examples are "potentially" undefined (I may have missed
    a defined one) in that they all might read the prior value of j (for a
    purpose other than determining the new value for j) without an
    intervening sequence point.

    I say "potentially" undefined because I suppose that if the change in j
    happens before any other "read" of j, the prior value is not being read,
    only the new one is. I'd still say "undefined" as a genaral answer
    since from the C point of view you can't be sure to avoid it.

    --
    Ben.
     
    Ben Bacarisse, Aug 18, 2010
    #6
  7. asdfghjk

    Shao Miller Guest

    On Aug 18, 12:05 pm, Mark Bluemel <> wrote:
    > Chris H wrote:
    > > See  and click at the bottom to se the answers.  It is a bit old now but
    > > it should answer your questions

    >
    > >http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm

    >
    > Hmmm... I'm not convinced
    >
    > That page claims that
    > <Quote>
    > uint16_t i = 10;
    > uint16_t j = 0;
    >
    > j=2;
    > printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >
    > The code is effectively running the following calculation - "I=10, j=3,
    > I * j++"
    >
    > </Quote>
    >
    > Firstly, I don't see why "uint16_t" is used in preference to plain
    > "int", especially since "%d" in printf requires int...
    >
    > Secondly, I'm fairly sure that the explanation makes some major
    > assumptions about the order of evaluation of function arguments, which
    > aren't necessarily true.
    >
    > Am I mistaken?

    I think the matter of 'printf' with the 'j++' was recently covered in
    the "C Test Incorrectly Uses printf() - Please Confirm" thread.
    Modification of 'j' but a read of 'j' in another argument could be
    considered to be a violation of C99's section 6.5, paragraph 2;
    leading to undefined behaviour. A compiler could refuse to translate
    the source code. At run-time, some extremely unexpected results are
    allowed of a conforming implementation.
     
    Shao Miller, Aug 18, 2010
    #7
  8. Ben Bacarisse <> writes:
    <snip>
    Code example: printf("%d\n", (i * j--) + (i * j));

    > I think all the examples are "potentially" undefined (I may have missed
    > a defined one) in that they all might read the prior value of j (for a
    > purpose other than determining the new value for j) without an
    > intervening sequence point.
    >
    > I say "potentially" undefined because I suppose that if the change in j
    > happens before any other "read" of j, the prior value is not being read,
    > only the new one is. I'd still say "undefined" as a genaral answer
    > since from the C point of view you can't be sure to avoid it.


    I take this last "potentially" bit back and revert to my original reply
    to Chris H. It is, at best, a sort of C sophistry at worst plain wrong.
    The code is undefined.

    I think any reference to the object that is changing will constitute a
    read of the "prior value" from the C standard point of view even if an
    implementation ensures that the change has, in practise, happened. Only
    at the next sequence point does the prior value change to being "the
    value" of the object.

    --
    Ben.
     
    Ben Bacarisse, Aug 18, 2010
    #8
  9. Mark Bluemel wrote:
    > Hmmm... I'm not convinced
    >
    > That page claims that
    > <Quote>
    > uint16_t i = 10;
    > uint16_t j = 0;
    >
    > j=2;
    > printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >
    > The code is effectively running the following calculation - "I=10, j=3,
    > I * j++"
    >
    > </Quote>
    >
    > Firstly, I don't see why "uint16_t" is used in preference to plain
    > "int", especially since "%d" in printf requires int...
    >
    > Secondly, I'm fairly sure that the explanation makes some major
    > assumptions about the order of evaluation of function arguments, which
    > aren't necessarily true.


    The above `printf` produces undefined behavior. Making assumptions about
    its order of evaluation makes no sense whatsoever.

    --
    Best regards.
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 18, 2010
    #9
  10. asdfghjk wrote:
    > #include <stdio.h>
    > main()
    > {
    > struct Data
    > {
    > int a;
    > int b;
    > } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    > struct Data *x = y;
    > int i;
    > for(i=0; i<4; i++)
    > {
    > x->a = x->b, ++x++->b;
    > printf("%d %d\t", y.a, y.b);
    > }
    > }
    >
    > I have confusion regarding the ++x++->b part.
    > The output is : 10 11 30 31 20 21 40 41


    The output of this code cannot be meaningfully explained from the point
    of view of C language. The `++x++` subexpression produces Undefined
    Behavior, meaning that even if this code generates some output, it can
    be safely perceived as essentially random.

    In fact, the code is not even guaranteed to compile, since the compilers
    are allowed to refuse to compile code with UB.

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 18, 2010
    #10
  11. Andrey Tarasevich wrote:
    > asdfghjk wrote:
    >> #include <stdio.h>
    >> main()
    >> {
    >> struct Data
    >> {
    >> int a;
    >> int b;
    >> } y[4] = { 1, 10, 3, 30, 2, 20, 4, 40};
    >> struct Data *x = y;
    >> int i;
    >> for(i=0; i<4; i++)
    >> {
    >> x->a = x->b, ++x++->b;
    >> printf("%d %d\t", y.a, y.b);
    >> }
    >> }
    >>
    >> I have confusion regarding the ++x++->b part.
    >> The output is : 10 11 30 31 20 21 40 41

    >
    > The output of this code cannot be meaningfully explained from the point
    > of view of C language. The `++x++` subexpression produces Undefined
    > Behavior, meaning that even if this code generates some output, it can
    > be safely perceived as essentially random.
    >
    > In fact, the code is not even guaranteed to compile, since the compilers
    > are allowed to refuse to compile code with UB.


    Scratch that. What I said above is incorrect. I misparsed the `++x++->b`
    subexpression.

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 18, 2010
    #11
  12. Chris H wrote:
    >
    > See and click at the bottom to se the answers. It is a bit old now but
    > it should answer your questions
    >
    > http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm


    Old or not, that page makes a major mistake of ignoring the critical
    qualitative difference between the Undefined Behavior and Unspecified
    Behavior in C. It takes a bunch of situations where the behavior is
    _undefined_ and proceeds to treat them as if the behavior is
    _unspecified_. While it might "work" in some (or many) cases in
    practice, the approach is nevertheless flawed and makes very little
    sense (or no sense whatsoever).

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 18, 2010
    #12
  13. asdfghjk

    Nick Guest

    Andrey Tarasevich <> writes:

    > Mark Bluemel wrote:
    >> Hmmm... I'm not convinced
    >>
    >> That page claims that
    >> <Quote>
    >> uint16_t i = 10;
    >> uint16_t j = 0;
    >>
    >> j=2;
    >> printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >>
    >> The code is effectively running the following calculation - "I=10,
    >> j=3, I * j++"
    >>
    >> </Quote>
    >>
    >> Firstly, I don't see why "uint16_t" is used in preference to plain
    >> "int", especially since "%d" in printf requires int...
    >>
    >> Secondly, I'm fairly sure that the explanation makes some major
    >> assumptions about the order of evaluation of function arguments,
    >> which aren't necessarily true.

    >
    > The above `printf` produces undefined behavior. Making assumptions
    > about its order of evaluation makes no sense whatsoever.


    I don't think it produces official undefined behaviour. It could,
    however, give you:
    10, 3, 20

    I think.
    --
    Online waterways route planner | http://canalplan.eu
    Plan trips, see photos, check facilities | http://canalplan.org.uk
     
    Nick, Aug 19, 2010
    #13
  14. Nick wrote:
    > Andrey Tarasevich <> writes:
    >
    >> Mark Bluemel wrote:
    >>> Hmmm... I'm not convinced
    >>>
    >>> That page claims that
    >>> <Quote>
    >>> uint16_t i = 10;
    >>> uint16_t j = 0;
    >>>
    >>> j=2;
    >>> printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >>>
    >>> The code is effectively running the following calculation - "I=10,
    >>> j=3, I * j++"
    >>>
    >>> </Quote>
    >>>
    >>> Firstly, I don't see why "uint16_t" is used in preference to plain
    >>> "int", especially since "%d" in printf requires int...
    >>>
    >>> Secondly, I'm fairly sure that the explanation makes some major
    >>> assumptions about the order of evaluation of function arguments,
    >>> which aren't necessarily true.

    >> The above `printf` produces undefined behavior. Making assumptions
    >> about its order of evaluation makes no sense whatsoever.

    >
    > I don't think it produces official undefined behaviour. It could,
    > however, give you:
    > 10, 3, 20


    Yes, it does produce official UB, no debate about it.

    Variable `j` is modified in `i * j++` and also read for a completely
    independent reason in `j`. This is a direct and straightforward
    violation if requirements of 6.5/2. I.e. there's an evaluation scenario
    in which these two events are not separated by a sequence point, meaning
    that the behavior us undefined.

    --
    Best regards.
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 19, 2010
    #14
  15. Andrey Tarasevich wrote:
    >>> The above `printf` produces undefined behavior. Making assumptions
    >>> about its order of evaluation makes no sense whatsoever.

    >> I don't think it produces official undefined behaviour. It could,
    >> however, give you:
    >> 10, 3, 20

    >
    > Yes, it does produce official UB, no debate about it.
    >
    > Variable `j` is modified in `i * j++` and also read for a completely
    > independent reason in `j`. This is a direct and straightforward
    > violation if requirements of 6.5/2. I.e. there's an evaluation scenario
    > in which these two events are not separated by a sequence point, meaning
    > that the behavior us undefined.


    BTW, a very similar issue was discussed on SO recently. You can refer to

    http://stackoverflow.com/questions/3450582/c-programming-is-this-undefined-behavior/3451334#3451334

    for more details.

    --
    Best regards.
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 19, 2010
    #15
  16. asdfghjk

    Nick Guest

    Andrey Tarasevich <> writes:

    > Nick wrote:
    >> Andrey Tarasevich <> writes:
    >>
    >>> Mark Bluemel wrote:
    >>>> Hmmm... I'm not convinced
    >>>>
    >>>> That page claims that
    >>>> <Quote>
    >>>> uint16_t i = 10;
    >>>> uint16_t j = 0;
    >>>>
    >>>> j=2;
    >>>> printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );
    >>>>
    >>>> The code is effectively running the following calculation - "I=10,
    >>>> j=3, I * j++"
    >>>>
    >>>> </Quote>
    >>>>
    >>>> Firstly, I don't see why "uint16_t" is used in preference to plain
    >>>> "int", especially since "%d" in printf requires int...
    >>>>
    >>>> Secondly, I'm fairly sure that the explanation makes some major
    >>>> assumptions about the order of evaluation of function arguments,
    >>>> which aren't necessarily true.
    >>> The above `printf` produces undefined behavior. Making assumptions
    >>> about its order of evaluation makes no sense whatsoever.

    >>
    >> I don't think it produces official undefined behaviour. It could,
    >> however, give you:
    >> 10, 3, 20

    >
    > Yes, it does produce official UB, no debate about it.
    >
    > Variable `j` is modified in `i * j++` and also read for a completely
    > independent reason in `j`. This is a direct and straightforward
    > violation if requirements of 6.5/2. I.e. there's an evaluation
    > scenario in which these two events are not separated by a sequence
    > point, meaning that the behavior us undefined.


    Yeah, you're right. I never write such horrible code, so I've never had
    to fix in my mind exactly when a comma is a sequence point and exactly
    when it isn't.
    --
    Online waterways route planner | http://canalplan.eu
    Plan trips, see photos, check facilities | http://canalplan.org.uk
     
    Nick, Aug 19, 2010
    #16
  17. asdfghjk

    Seebs Guest

    On 2010-08-19, Nick <> wrote:
    >>> printf("i = %d, j = %d, i * j++ = %d \n", i, j, i* j++ );


    > I don't think it produces official undefined behaviour.


    It does.

    There's no sequence point between the access to j and the modification
    of j in "j++". Therefore the behavior is undefined.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Aug 19, 2010
    #17
  18. Nick <> writes:
    [...]
    > Yeah, you're right. I never write such horrible code, so I've never had
    > to fix in my mind exactly when a comma is a sequence point and exactly
    > when it isn't.


    A comma is a sequence point only when it's a comma operator.
    (A comma operator evaluates its left argument and discards the
    result, then evaluates its right arguments and yields its results.)

    The commas separating arguments in function calls are not operators;
    they're just part of the syntax of a function call.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Aug 19, 2010
    #18
    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. suzy
    Replies:
    3
    Views:
    472
  2. srikanth
    Replies:
    14
    Views:
    560
    vijay
    Jul 10, 2003
  3. John Dean
    Replies:
    4
    Views:
    272
    John Dean
    Sep 15, 2003
  4. Vittal

    Can somebody explain?

    Vittal, Aug 10, 2004, in forum: Perl Misc
    Replies:
    6
    Views:
    163
    Vittal
    Aug 12, 2004
  5. Steve
    Replies:
    3
    Views:
    235
    C.DeRykus
    Feb 24, 2010
Loading...

Share This Page