more on operands' binding and evaluation order

Discussion in 'C Programming' started by Ersek, Laszlo, Jun 21, 2010.

  1. Hi,

    given the following code,

    #include <stdio.h>

    static int *
    ip_incr(int id, int **i)
    {
    (void)fprintf(stdout, "%d\n", id);
    return ++*i;
    }

    int main(void)
    {
    int x[4] = { 0 },
    *a = x,
    *b = x + 1,
    *c = x + 2;

    *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    return 0;
    }

    am I right to think that the program is well defined, and that the output
    is (provided no output error occurs)

    ----v----
    A
    B
    C
    0 7 7 7
    ----^----

    where [ABC] is any permutation of [123]?

    Thanks,
    lacos
     
    Ersek, Laszlo, Jun 21, 2010
    #1
    1. Advertising

  2. Ersek, Laszlo

    Eric Sosman Guest

    On 6/21/2010 8:29 AM, Ersek, Laszlo wrote:
    > Hi,
    >
    > given the following code,
    >
    > #include <stdio.h>
    >
    > static int *
    > ip_incr(int id, int **i)
    > {
    > (void)fprintf(stdout, "%d\n", id);
    > return ++*i;
    > }
    >
    > int main(void)
    > {
    > int x[4] = { 0 },
    > *a = x,
    > *b = x + 1,
    > *c = x + 2;
    >
    > *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    > (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    > return 0;
    > }
    >
    > am I right to think that the program is well defined, and that the
    > output is (provided no output error occurs)
    >
    > ----v----
    > A
    > B
    > C
    > 0 7 7 7
    > ----^----
    >
    > where [ABC] is any permutation of [123]?


    As far as I can see, yes. (Although the "any permutation"
    bit clashes somewhat with "well defined.") What aspects do you
    find suspicious?

    --
    Eric Sosman
    lid
     
    Eric Sosman, Jun 21, 2010
    #2
    1. Advertising

  3. On Mon, 21 Jun 2010, Eric Sosman wrote:

    > On 6/21/2010 8:29 AM, Ersek, Laszlo wrote:
    >> Hi,
    >>
    >> given the following code,
    >>
    >> #include <stdio.h>
    >>
    >> static int *
    >> ip_incr(int id, int **i)
    >> {
    >> (void)fprintf(stdout, "%d\n", id);
    >> return ++*i;
    >> }
    >>
    >> int main(void)
    >> {
    >> int x[4] = { 0 },
    >> *a = x,
    >> *b = x + 1,
    >> *c = x + 2;
    >>
    >> *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    >> (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    >> return 0;
    >> }
    >>
    >> am I right to think that the program is well defined, and that the
    >> output is (provided no output error occurs)
    >>
    >> ----v----
    >> A
    >> B
    >> C
    >> 0 7 7 7
    >> ----^----
    >>
    >> where [ABC] is any permutation of [123]?

    >
    > As far as I can see, yes. (Although the "any permutation"
    > bit clashes somewhat with "well defined.")


    Indeed, I should have asked if there was "no undefined behavior" in this
    program.


    > What aspects do you find suspicious?


    I wrote the snippet for a friend in order to demonstrate the difference
    between operand binding and order of evaluation. In particular that the
    "right-associativity" of the assignment operator doesn't determine the
    order of calls to ip_incr(). I just wanted to double-check the sanity of
    my code with your help.

    (BTW, compiling the program with gcc (Debian 4.3.2-1.1), ABC resolves to
    123, which is the exact reverse of the "intuitive" (in fact unspecified)
    order that my friend assumed (in my understanding).)

    Thank you very much.
    lacos
     
    Ersek, Laszlo, Jun 21, 2010
    #3
  4. Ersek, Laszlo

    Tim Rentsch Guest

    "Ersek, Laszlo" <> writes:

    > given the following code,
    >
    > #include <stdio.h>
    >
    > static int *
    > ip_incr(int id, int **i)
    > {
    > (void)fprintf(stdout, "%d\n", id);
    > return ++*i;
    > }
    >
    > int main(void)
    > {
    > int x[4] = { 0 },
    > *a = x,
    > *b = x + 1,
    > *c = x + 2;
    >
    > *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    > (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    > return 0;
    > }
    >
    > am I right to think that the program is well defined, and that the
    > output is (provided no output error occurs)
    >
    > ----v----
    > A
    > B
    > C
    > 0 7 7 7
    > ----^----
    >
    > where [ABC] is any permutation of [123]?


    The program seems more complicated than it needs to be to
    illustrate what I think you're trying to illustrate. However,
    unless there is some obscure condition I've missed, it has no
    undefined behavior.
     
    Tim Rentsch, Jun 22, 2010
    #4
  5. On 21 Giu, 14:29, "Ersek, Laszlo" <> wrote:
    > Hi,
    >
    > given the following code,
    >
    > #include <stdio.h>


    nice example!
    I think it has no undefined behavior, as others, more experienced than
    me, have already said.
    May I ask why you choose to use fprintf(stdout,...) instead of
    printf ?
    (Given the illustrative nature of the example, using printf may render
    the code a little bit simpler)
     
    Luca Forlizzi, Jun 22, 2010
    #5
  6. On Mon, 21 Jun 2010, Kenneth Brody wrote:

    >>> On 6/21/2010 8:29 AM, Ersek, Laszlo wrote:


    >>>> #include <stdio.h>
    >>>>
    >>>> static int *
    >>>> ip_incr(int id, int **i)
    >>>> {
    >>>> (void)fprintf(stdout, "%d\n", id);
    >>>> return ++*i;
    >>>> }
    >>>>
    >>>> int main(void)
    >>>> {
    >>>> int x[4] = { 0 },
    >>>> *a = x,
    >>>> *b = x + 1,
    >>>> *c = x + 2;
    >>>>
    >>>> *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    >>>> (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    >>>> return 0;
    >>>> }


    > And MSVC (version 14), even with optimizations supposedly disabled
    > (/Od), optimizes ip_incr() away, and generates the equivalent of:
    >
    > int main(void)
    > {
    > fprintf(stdout,"%d\n",3);
    > fprintf(stdout,"%d\n",2);
    > fprintf(stdout,"%d\n",1);
    > fprintf(stdout,"%d %d %d %d\n",0,7,7,7);
    > return 0;
    > }


    I was actually a bit curious what evaluation orders different compilers
    choose. Thanks for the info!

    lacos
     
    Ersek, Laszlo, Jun 22, 2010
    #6
  7. On Mon, 21 Jun 2010, Tim Rentsch wrote:

    > "Ersek, Laszlo" <> writes:
    >
    >> #include <stdio.h>
    >>
    >> static int *
    >> ip_incr(int id, int **i)
    >> {
    >> (void)fprintf(stdout, "%d\n", id);
    >> return ++*i;
    >> }
    >>
    >> int main(void)
    >> {
    >> int x[4] = { 0 },
    >> *a = x,
    >> *b = x + 1,
    >> *c = x + 2;
    >>
    >> *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    >> (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    >> return 0;
    >> }


    > The program seems more complicated than it needs to be to
    > illustrate what I think you're trying to illustrate.


    Yes, it is positively not "minimal". We started with

    a = b = c = 7;

    then (after changing types accordingly)

    *++a = *++b = *++c = 7;

    and then I added the fprintf()'s. There are better ways, probably. Care to
    show one? :)


    > However, unless there is some obscure condition I've missed, it has no
    > undefined behavior.


    Thanks!
    lacos
     
    Ersek, Laszlo, Jun 22, 2010
    #7
  8. On Mon, 21 Jun 2010, Luca Forlizzi wrote:

    > On 21 Giu, 14:29, "Ersek, Laszlo" <> wrote:
    >> Hi,
    >>
    >> given the following code,
    >>
    >> #include <stdio.h>

    >
    > nice example!


    Thanks :)


    > I think it has no undefined behavior, as others, more experienced than
    > me, have already said.
    > May I ask why you choose to use fprintf(stdout,...) instead of
    > printf ?


    I like to be able to search for the stream's name.


    > (Given the illustrative nature of the example, using printf may render
    > the code a little bit simpler)


    In general I don't believe in "simple examples", as in omitting error
    handling and working in a different style than otherwise. Missing error
    handling creates a false impression. Truth to be told, I don't really like
    that I threw away the return values of the fprintf() calls. Once the test
    program compiles, it should also honor write errors, eg.

    $ ./try >/dev/full

    at least with a nonzero exit status.

    Cheers,
    lacos
     
    Ersek, Laszlo, Jun 22, 2010
    #8
  9. Ersek, Laszlo

    Eric Sosman Guest

    On 6/22/2010 8:33 AM, Ersek, Laszlo wrote:
    > [...]
    > Yes, it is positively not "minimal". We started with
    >
    > a = b = c = 7;
    >
    > then (after changing types accordingly)
    >
    > *++a = *++b = *++c = 7;
    >
    > and then I added the fprintf()'s. There are better ways, probably. Care
    > to show one? :)


    If the goal is to show that associativity et al. do not govern
    evaluation order, I'd suggest stripping away side-effects that don't
    really matter and may just act as red herrings. Something like

    #include <stdio.h>

    static int index(int idx) {
    printf ("idx = %d\n", idx);
    return idx;
    }

    int main(void) {
    int array[4] = { 0 };
    array[index(1)] = array[index(2)] = array[index(3)] = 7;
    printf ("array = { %d, %d, %d, %d }\n",
    array[0], array[1], array[2], array[3]);
    return 0;
    }

    .... would be similar in spirit to your original, but without the
    distractions of pointers-to-pointers and so on.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Jun 22, 2010
    #9
  10. On Tue, 22 Jun 2010, Eric Sosman wrote:

    > array[index(1)] = array[index(2)] = array[index(3)] = 7;


    Great, thanks!
    lacos
     
    Ersek, Laszlo, Jun 22, 2010
    #10
  11. Ersek, Laszlo

    Tim Rentsch Guest

    "Ersek, Laszlo" <> writes:

    > On Mon, 21 Jun 2010, Tim Rentsch wrote:
    >
    >> "Ersek, Laszlo" <> writes:
    >>
    >>> #include <stdio.h>
    >>>
    >>> static int *
    >>> ip_incr(int id, int **i)
    >>> {
    >>> (void)fprintf(stdout, "%d\n", id);
    >>> return ++*i;
    >>> }
    >>>
    >>> int main(void)
    >>> {
    >>> int x[4] = { 0 },
    >>> *a = x,
    >>> *b = x + 1,
    >>> *c = x + 2;
    >>>
    >>> *ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
    >>> (void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
    >>> return 0;
    >>> }

    >
    >> The program seems more complicated than it needs to be to
    >> illustrate what I think you're trying to illustrate.

    >
    > [snip] Care to show one? :)


    I would probably write something like this:

    #include <stdio.h>

    static int x[4];

    int *
    px( int k ){
    printf( "%d\n", k );
    return x+k;
    }

    int
    main(){
    *px(1) = *px(2) = *px(3) = 7;
    printf( "%d %d %d %d\n", x[0], x[1], x[2], x[3] );
    return 0;
    }
     
    Tim Rentsch, Jun 22, 2010
    #11
  12. On Tue, 22 Jun 2010, Tim Rentsch wrote:

    > #include <stdio.h>
    >
    > static int x[4];
    >
    > int *
    > px( int k ){
    > printf( "%d\n", k );
    > return x+k;
    > }
    >
    > int
    > main(){
    > *px(1) = *px(2) = *px(3) = 7;
    > printf( "%d %d %d %d\n", x[0], x[1], x[2], x[3] );
    > return 0;
    > }


    Thanks!
    lacos
     
    Ersek, Laszlo, Jun 23, 2010
    #12
    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. Ilias Lazaridis
    Replies:
    2
    Views:
    393
    Ilias Lazaridis
    Apr 24, 2005
  2. Replies:
    26
    Views:
    664
    Mark McIntyre
    Jun 15, 2007
  3. Replies:
    4
    Views:
    414
  4. Ilias Lazaridis
    Replies:
    74
    Views:
    763
    Ilias Lazaridis
    Apr 4, 2005
  5. Ilias Lazaridis
    Replies:
    18
    Views:
    335
    Bill Guindon
    Apr 9, 2005
Loading...

Share This Page