Knowing your sequence points

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • akarl

    #1

    Knowing your sequence points

    Hi all,

    Why do I get a warning from gcc with the following program?

    [test]$ cat test.c
    #include <stdio.h>

    int f(int n)
    {
    return n;
    }


    int main(void)
    {
    int n = 0;

    printf("%i\n", f(n++) + n);
    return 0;
    }

    [test]$ gcc -Wall test.c
    test.c: In function ‘main’:
    test.c:13: warning: operation on ‘n’ may be undefined

    One of the sequence point cases is defined as: "The point of calling a
    function, after evaluating its arguments." If I got it right, that rule
    can be applied to `f(n++)' which is evaluated before `n' since addition
    is left associative. I can't see the ambiguity here.


    August

    (I would never write this kind of code in practice, but it's good to
    know how the standard is defined.)
  • pete

    #2
    Re: Knowing your sequence points

    akarl wrote:[color=blue]
    >
    > Hi all,
    >
    > Why do I get a warning from gcc with the following program?
    >
    > [test]$ cat test.c
    > #include <stdio.h>
    >
    > int f(int n)
    > {
    > return n;
    > }
    >
    > int main(void)
    > {
    > int n = 0;
    >
    > printf("%i\n", f(n++) + n);
    > return 0;
    > }
    >
    > [test]$ gcc -Wall test.c
    > test.c: In function ‘main’:
    > test.c:13: warning: operation on ‘n’ may be undefined
    >
    > One of the sequence point cases is defined as: "The point of calling a
    > function, after evaluating its arguments."
    > If I got it right, that rule
    > can be applied to `f(n++)' which is evaluated before
    > `n' since addition is left associative.
    > I can't see the ambiguity here.[/color]

    That's not what left associative means.

    --
    pete

    Comment

    • akarl

      #3
      Re: Knowing your sequence points

      pete wrote:[color=blue]
      > akarl wrote:
      >[color=green]
      >>Hi all,
      >>
      >>Why do I get a warning from gcc with the following program?
      >>
      >>[test]$ cat test.c
      >>#include <stdio.h>
      >>
      >>int f(int n)
      >>{
      >> return n;
      >>}
      >>
      >>int main(void)
      >>{
      >> int n = 0;
      >>
      >> printf("%i\n", f(n++) + n);
      >> return 0;
      >>}
      >>
      >>[test]$ gcc -Wall test.c
      >>test.c: In function ‘main’:
      >>test.c:13: warning: operation on ‘n’ may be undefined
      >>
      >>One of the sequence point cases is defined as: "The point of calling a
      >>function, after evaluating its arguments."
      >>If I got it right, that rule
      >>can be applied to `f(n++)' which is evaluated before
      >>`n' since addition is left associative.
      >>I can't see the ambiguity here.[/color]
      >
      >
      > That's not what left associative means.[/color]

      Yes, of course (only one addition operation). How stupid of me. So the
      ambiguity here is that the *evaluation order* of the operands of `+' is
      unspecified, right?

      August

      Comment

      • Jack Klein

        #4
        Re: Knowing your sequence points

        On Thu, 11 Aug 2005 02:15:14 GMT, akarl <fusionfive@com hem.se> wrote
        in comp.lang.c:
        [color=blue]
        > Hi all,
        >
        > Why do I get a warning from gcc with the following program?
        >
        > [test]$ cat test.c
        > #include <stdio.h>
        >
        > int f(int n)
        > {
        > return n;
        > }
        >
        >
        > int main(void)
        > {
        > int n = 0;
        >
        > printf("%i\n", f(n++) + n);
        > return 0;
        > }
        >
        > [test]$ gcc -Wall test.c
        > test.c: In function ‘main’:
        > test.c:13: warning: operation on ‘n’ may be undefined[/color]

        Yes, the operation on 'n' may be undefined. The standard says:

        "Between the previous and next sequence point an object shall have its
        stored value modified at most once by the evaluation of an expression.
        Furthermore, the prior value shall be read only to determine the value
        to be stored."

        The printf() call in your call does not modify the value of 'n' more
        than once. The expression 'n++' modifies 'n' exactly once, and uses
        the original value of 'n' only for the purpose of computing the new
        value. But the '+ n' subexpression attempts to access the prior value
        of 'n' in a way that is not used in the computation of the new value.
        [color=blue]
        > One of the sequence point cases is defined as: "The point of calling a
        > function, after evaluating its arguments." If I got it right, that rule
        > can be applied to `f(n++)' which is evaluated before `n' since addition
        > is left associative. I can't see the ambiguity here.[/color]

        No, you are wrong, associatively has nothing at all to do with order
        of evaluation. Only sequence points impose an order of evaluation.
        [color=blue]
        > August
        >
        > (I would never write this kind of code in practice, but it's good to
        > know how the standard is defined.)[/color]

        Let's take an example that doesn't have undefined behavior:

        #include <stdio.h>

        int f1(void)
        {
        puts("function 1\n");
        return 1;
        }

        int f2(void)
        {
        puts("function 1\n");
        return 2;
        }

        int main(void)
        {
        printf("the sum is %d\n", f1() + f2());
        return 0;
        }

        This function does not define or contain any objects at all, so the
        paragraph I quoted from the standard certainly does not apply.

        Because the order of evaluation between sequence points is
        unspecified, the output could be either of the following two
        sequences, and must be one of the two:

        function 1
        function 2
        the sum is 3

        ....or:

        function 2
        function 1
        the sum is 3

        In fact, it may change between one and the other if you change the
        settings you use to invoke your compiler, for example enable or
        disable optimization.

        If just so happens that if your compiler evaluates the subexpression
        'f(n++)' first, the result is defined because there is a sequence
        point imposed by calling the function before the '+ n' subexpression
        reads the value of 'n' again.

        But if your compiler evaluates 'n' in the '+ n' subexpression before
        evaluating the 'f(n++)' subexpression, there is no sequence point
        between the unrelated read and the modification, the behavior is
        undefined.

        Finally, since the order of evaluation is something the standard
        states is unspecified, it means that the compiler does not have to
        tell you which order it uses, and is free to change it based on
        settings, the day of the week, or the phase of the moon.

        Since one of the unspecified paths generates undefined behavior, the
        whole thing should be treated as undefined.

        --
        Jack Klein
        Home: http://JK-Technology.Com
        FAQs for
        comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
        comp.lang.c++ http://www.parashift.com/c++-faq-lite/
        alt.comp.lang.l earn.c-c++

        Comment

        • pete

          #5
          Re: Knowing your sequence points

          akarl wrote:[color=blue]
          >
          > pete wrote:[color=green]
          > > akarl wrote:[/color][/color]
          [color=blue][color=green][color=darkred]
          > >> printf("%i\n", f(n++) + n);[/color][/color][/color]
          [color=blue][color=green][color=darkred]
          > >>test.c:13: warning: operation on ‘n’ may be undefined[/color][/color][/color]
          [color=blue][color=green][color=darkred]
          > >>`f(n++)' which is evaluated before
          > >>`n' since addition is left associative.
          > >>I can't see the ambiguity here.[/color]
          > >
          > >
          > > That's not what left associative means.[/color]
          >
          > Yes, of course (only one addition operation). How stupid of me. So the
          > ambiguity here is that the *evaluation order*
          > of the operands of `+' is unspecified, right?[/color]

          Yes. There are rules that say that modifying n
          and reading n between sequence points, is undefined,
          even though it might seem to be only unspecified.

          I think it's good to avoid side effects in function arguments.
          I absentmindedly used an argument with side effects in the
          Re: A question on string literals
          thread, thereby confusing Default User.
          It would have been more better if I had
          incremented the pointer prior to the function call
          instead of in the function call.

          --
          pete

          Comment

          • Martin Ambuhl

            #6
            Re: Knowing your sequence points

            akarl wrote:[color=blue]
            > Hi all,
            >
            > Why do I get a warning from gcc with the following program?[/color]
            [...][color=blue]
            > printf("%i\n", f(n++) + n);[/color]
            [...][color=blue]
            > test.c:13: warning: operation on ‘n’ may be undefined[/color]

            Because the the value of 'f(n++) + n' is undefined.
            [color=blue]
            > One of the sequence point cases is defined as: "The point of calling
            > a function, after evaluating its arguments." If I got it right, that
            > rule can be applied to `f(n++)' which is evaluated before `n' since
            > addition is left associative. I can't see the ambiguity here.[/color]

            The order of evaluation of the operands f(n++) and n is not defined.
            Associativity (which isn't a C concept, anyway) doesn't enter into it.

            Comment

            • Suman

              #7
              Re: Knowing your sequence points


              Jack Klein wrote:[color=blue]
              > On Thu, 11 Aug 2005 02:15:14 GMT, akarl <fusionfive@com hem.se> wrote
              > in comp.lang.c:
              >[color=green]
              > > Hi all,
              > >
              > > Why do I get a warning from gcc with the following program?
              > >
              > > [test]$ cat test.c
              > > #include <stdio.h>
              > >
              > > int f(int n)
              > > {
              > > return n;
              > > }
              > >
              > >
              > > int main(void)
              > > {
              > > int n = 0;
              > >
              > > printf("%i\n", f(n++) + n);
              > > return 0;
              > > }
              > >
              > > [test]$ gcc -Wall test.c
              > > test.c: In function 'main':
              > > test.c:13: warning: operation on 'n' may be undefined[/color]
              >
              > Yes, the operation on 'n' may be undefined. The standard says:
              >
              > "Between the previous and next sequence point an object shall have its
              > stored value modified at most once by the evaluation of an expression.
              > Furthermore, the prior value shall be read only to determine the value
              > to be stored."
              >
              > The printf() call in your call does not modify the value of 'n' more
              > than once. The expression 'n++' modifies 'n' exactly once, and uses
              > the original value of 'n' only for the purpose of computing the new
              > value. But the '+ n' subexpression attempts to access the prior value
              > of 'n' in a way that is not used in the computation of the new value.
              >[color=green]
              > > One of the sequence point cases is defined as: "The point of calling a
              > > function, after evaluating its arguments." If I got it right, that rule
              > > can be applied to `f(n++)' which is evaluated before `n' since addition
              > > is left associative. I can't see the ambiguity here.[/color]
              >
              > No, you are wrong, associatively has nothing at all to do with order
              > of evaluation. Only sequence points impose an order of evaluation.
              >[color=green]
              > > August
              > >
              > > (I would never write this kind of code in practice, but it's good to
              > > know how the standard is defined.)[/color]
              >
              > Let's take an example that doesn't have undefined behavior:
              >
              > #include <stdio.h>
              >
              > int f1(void)
              > {
              > puts("function 1\n");
              > return 1;
              > }
              >
              > int f2(void)
              > {
              > puts("function 1\n");
              > return 2;
              > }
              >
              > int main(void)
              > {
              > printf("the sum is %d\n", f1() + f2());
              > return 0;
              > }
              >
              > This function does not define or contain any objects at all, so the
              > paragraph I quoted from the standard certainly does not apply.
              >
              > Because the order of evaluation between sequence points is
              > unspecified, the output could be either of the following two
              > sequences, and must be one of the two:
              >
              > function 1
              > function 2
              > the sum is 3
              >
              > ...or:
              >
              > function 2
              > function 1
              > the sum is 3[/color]

              <nitpick>
              or more likely:
              function 1
              function 1
              the sum is 3
              </nitpick>
              [color=blue]
              > In fact, it may change between one and the other if you change the
              > settings you use to invoke your compiler, for example enable or
              > disable optimization.
              >
              > If just so happens that if your compiler evaluates the subexpression
              > 'f(n++)' first, the result is defined because there is a sequence
              > point imposed by calling the function before the '+ n' subexpression
              > reads the value of 'n' again.
              >
              > But if your compiler evaluates 'n' in the '+ n' subexpression before
              > evaluating the 'f(n++)' subexpression, there is no sequence point
              > between the unrelated read and the modification, the behavior is
              > undefined.
              >
              > Finally, since the order of evaluation is something the standard
              > states is unspecified, it means that the compiler does not have to
              > tell you which order it uses, and is free to change it based on
              > settings, the day of the week, or the phase of the moon.
              >
              > Since one of the unspecified paths generates undefined behavior, the
              > whole thing should be treated as undefined.
              >
              > --
              > Jack Klein
              > Home: http://JK-Technology.Com
              > FAQs for
              > comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
              > comp.lang.c++ http://www.parashift.com/c++-faq-lite/
              > alt.comp.lang.l earn.c-c++
              > http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html[/color]

              Comment

              • Jack Klein

                #8
                Re: Knowing your sequence points

                On 10 Aug 2005 23:55:56 -0700, "Suman" <skarpio@gmail. com> wrote in
                comp.lang.c:
                [color=blue]
                > Jack Klein wrote:[/color]

                [snip]
                [color=blue][color=green]
                > > Let's take an example that doesn't have undefined behavior:
                > >
                > > #include <stdio.h>
                > >
                > > int f1(void)
                > > {
                > > puts("function 1\n");
                > > return 1;
                > > }
                > >
                > > int f2(void)
                > > {
                > > puts("function 1\n");
                > > return 2;
                > > }
                > >
                > > int main(void)
                > > {
                > > printf("the sum is %d\n", f1() + f2());
                > > return 0;
                > > }
                > >
                > > This function does not define or contain any objects at all, so the
                > > paragraph I quoted from the standard certainly does not apply.
                > >
                > > Because the order of evaluation between sequence points is
                > > unspecified, the output could be either of the following two
                > > sequences, and must be one of the two:
                > >
                > > function 1
                > > function 2
                > > the sum is 3
                > >
                > > ...or:
                > >
                > > function 2
                > > function 1
                > > the sum is 3[/color]
                >
                > <nitpick>
                > or more likely:
                > function 1
                > function 1
                > the sum is 3
                > </nitpick>[/color]

                Kind of takes the away the whole point of the example, doesn't it?
                Makes it really, really indeterminate!

                Thanks, Suman, nice catch.

                --
                Jack Klein
                Home: http://JK-Technology.Com
                FAQs for
                comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
                comp.lang.c++ http://www.parashift.com/c++-faq-lite/
                alt.comp.lang.l earn.c-c++

                Comment

                Working...