i++ * i++

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

    #16
    Re: i++ * i++

    On 16 Mar 2006 07:49:12 -0800, in comp.lang.c , "rohit"
    <rohit1712@gmai l.com> wrote:
    [color=blue]
    >#define PRODUCT(x) (x*x)
    > j = PRODUCT(i++);
    >The output is 9 and 49
    >shouldn't the answer be 12 and 20?[/color]

    this is a FAQ

    Mark McIntyre
    --
    "Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it."
    --Brian Kernighan

    Comment

    • Mark McIntyre

      #17
      Re: i++ * i++

      On Thu, 16 Mar 2006 23:14:33 +0100, in comp.lang.c , arnold
      <arnold@example .net> wrote:
      [color=blue]
      >The reason i++ is used twice is because its a macro?[/color]

      Not really - its used twice because thats what the OP programmed for.
      [color=blue]
      >dont know much
      >about macros:( meaning the argument is literally copied into the
      >expression of the macro hence being duplicated?[/color]

      Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
      is literally replaced by i++ * i++
      [color=blue]
      >So if it had been a function, it would be given the value i and then, in
      >the next call, i+2. That would have given the values 9 and 25, and there
      >would be no undefined behaviour. correct or mistaken again?[/color]

      If it had been a function it would have been unspecified which
      increment was done first, but the result would have been well defined.
      This is because although the order of evaluation of function arguments
      is unspecified, there's a sequence point at the function call.
      Mark McIntyre
      --
      "Debugging is twice as hard as writing the code in the first place.
      Therefore, if you write the code as cleverly as possible, you are,
      by definition, not smart enough to debug it."
      --Brian Kernighan

      Comment

      • Keith Thompson

        #18
        Re: i++ * i++

        Mark McIntyre <markmcintyre@s pamcop.net> writes:[color=blue]
        > On Thu, 16 Mar 2006 23:14:33 +0100, in comp.lang.c , arnold
        > <arnold@example .net> wrote:
        >[color=green]
        >>The reason i++ is used twice is because its a macro?[/color]
        >
        > Not really - its used twice because thats what the OP programmed for.
        >[color=green]
        >>dont know much
        >>about macros:( meaning the argument is literally copied into the
        >>expression of the macro hence being duplicated?[/color]
        >
        > Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
        > is literally replaced by i++ * i++
        >[color=green]
        >>So if it had been a function, it would be given the value i and then, in
        >>the next call, i+2. That would have given the values 9 and 25, and there
        >>would be no undefined behaviour. correct or mistaken again?[/color]
        >
        > If it had been a function it would have been unspecified which
        > increment was done first, but the result would have been well defined.
        > This is because although the order of evaluation of function arguments
        > is unspecified, there's a sequence point at the function call.[/color]

        Yes, but there are no sequence points between the evaluations of the
        arguments. This:
        func(i++, i++);
        invokes undefined behavior because it modifies i twice between
        sequence points (regardless of what happens inside func()).

        --
        Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
        San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
        We must do something. This is something. Therefore, we must do this.

        Comment

        • Keith Thompson

          #19
          Re: i++ * i++

          arnold <arnold@example .net> writes:[color=blue]
          > Chris Smith wrote:
          >[color=green]
          > > The macro just expanded PRODUCT(i++) to "i++ * i++", which I assume you
          > > knew, since you wrote the expanded form in the subject line. It's the
          > > multiple modifications to i between sequence points that yield the
          > > undefined behavior.[/color]
          >
          > Chris, it wasn't me, it was this other guy called rohit, the OP:)
          >
          >[color=green]
          > > More importantly, your macro expands to increment i twice, not just
          > > once. The variable i is therefore modified twice, in an undefined order
          > > and perhaps even in parallel, and the result is therefore completely
          > > undefined.[/color]
          >
          > The reason i++ is used twice is because its a macro? dont know much
          > about macros:( meaning the argument is literally copied into the
          > expression of the macro hence being duplicated?[/color]

          The reason i++ is used twice is because of what the macro expands to.

          Macro expansion is just textual replacement. It works on tokens, not
          on expressions.

          Consider this program, which demonstrates that Douglas Adams was
          right, even without using base 13:
          =============== =============== ==
          #include <stdio.h>

          #define SIX 1+5
          #define NINE 8+1

          int main(void)
          {
          printf("%d * %d = %d\n", SIX, NINE, SIX * NINE);
          return 0;
          }
          =============== =============== ==

          See if you can figure out what the output should be, and why, without
          running it. Then compile and run it, and see if you were correct.
          [color=blue]
          > So if it had been a function, it would be given the value i and then,
          > in the next call, i+2. That would have given the values 9 and 25, and
          > there would be no undefined behaviour. correct or mistaken again?[/color]

          Mistaken; see my other response in this thread.

          --
          Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
          San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
          We must do something. This is something. Therefore, we must do this.

          Comment

          • arnold

            #20
            Re: i++ * i++

            Mark McIntyre wrote:

            Sorry but what you are saying did not make things cleare for me, so let
            me try summarise it a little differently.
            [color=blue]
            > Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
            > is literally replaced by i++ * i++[/color]

            a literal replacement for each user of the paramter argument?
            So, if the paramtere had been: (i++/23) then the expression would have been

            (i++/23) * (i++/23)

            [color=blue]
            > If it had been a function it would have been unspecified which
            > increment was done first, but the result would have been well defined.
            > This is because although the order of evaluation of function arguments
            > is unspecified, there's a sequence point at the function call.[/color]

            Just to make sure I understand you correctly, given the following

            func1(int x) { return(x * x); }

            i=3;
            func1(i++); -> return(3 * 3) => 9
            func1(++i); -> return(5 * 5) => 25

            So the compiler can optimise, reorganise how ever it likes but the
            logical effect of it is as described above, correct?

            arnold

            Comment

            • Keith Thompson

              #21
              Re: i++ * i++

              Keith Thompson <kst-u@mib.org> writes:
              [...][color=blue]
              > Macro expansion is just textual replacement. It works on tokens, not
              > on expressions.
              >
              > Consider this program, which demonstrates that Douglas Adams was
              > right, even without using base 13:
              > =============== =============== ==
              > #include <stdio.h>
              >
              > #define SIX 1+5
              > #define NINE 8+1
              >
              > int main(void)
              > {
              > printf("%d * %d = %d\n", SIX, NINE, SIX * NINE);
              > return 0;
              > }
              > =============== =============== ==[/color]

              Which is why, in a macro definition, each reference to each argument
              should normally be parenthesized, as should the entire expansion.

              For example, this:

              #define SUM(x, y) x + y

              is potentially very dangerous; it should be:

              #define SUM(x, y) ((x) + (y))

              --
              Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
              San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
              We must do something. This is something. Therefore, we must do this.

              Comment

              • arnold

                #22
                Re: i++ * i++

                arnold wrote:[color=blue]
                > Just to make sure I understand you correctly, given the following
                >
                > func1(int x) { return(x * x); }
                >
                > i=3;
                > func1(i++); -> return(3 * 3) => 9
                > func1(++i); -> return(5 * 5) => 25
                >
                > So the compiler can optimise, reorganise how ever it likes but the
                > logical effect of it is as described above, correct?[/color]

                A couple of follow up questions, I was reading the faq on expressions
                and some questions came to mind about it.

                What you are saying about undefined behaviour is that, if f.ex. an i++
                or ++i is used twice in an expression it causes undefined behaviour,
                such as by now the famous
                i++ * i++
                but if its
                i++ * j++
                then its defined

                in question 3.3 it is stated

                "neither i++ nor ++i is the same as i+1. If you want to increment i, use
                i=i+1, i+=1, i++, or ++i, not some combination."

                I am not sure I understand it, is that what I said above, dont use a
                variable twice in an expression?

                question 3.4

                "Operator precedence and explicit parentheses impose only a partial
                ordering on the evaluation of an expression."
                I dont quite understand this, If I write

                ((3 + 4) * 2)

                in my mind, the paretheses causes the following evaluation

                (3 + 2) => 5 then
                (5 * 2) => 10

                because the second statement can not be evaluated before the first is
                evaluated. So does the fact contradict this assumption?

                arnold

                Comment

                • Keith Thompson

                  #23
                  Re: i++ * i++

                  arnold <arnold@example .net> writes:[color=blue]
                  > arnold wrote:[color=green]
                  >> Just to make sure I understand you correctly, given the following
                  >> func1(int x) { return(x * x); }
                  >> i=3;
                  >> func1(i++); -> return(3 * 3) => 9
                  >> func1(++i); -> return(5 * 5) => 25
                  >> So the compiler can optimise, reorganise how ever it likes but the
                  >> logical effect of it is as described above, correct?[/color]
                  >
                  > A couple of follow up questions, I was reading the faq on expressions
                  > and some questions came to mind about it.
                  >
                  > What you are saying about undefined behaviour is that, if f.ex. an i++
                  > or ++i is used twice in an expression it causes undefined behaviour,
                  > such as by now the famous
                  > i++ * i++
                  > but if its
                  > i++ * j++
                  > then its defined[/color]

                  Right. Note that, in some more complex cases, it can be difficult to
                  determine whether an expression exhibits undefined behavior just by
                  looking at it. For example:

                  arr[i]++ * arr[j]++

                  is ok if i != j, but if they're equal, it exhibits undefined behavior
                  (because it modifies an object, namely arr[i], twice).
                  [color=blue]
                  > in question 3.3 it is stated
                  >
                  > "neither i++ nor ++i is the same as i+1. If you want to increment i,
                  > use i=i+1, i+=1, i++, or ++i, not some combination."
                  >
                  > I am not sure I understand it, is that what I said above, dont use a
                  > variable twice in an expression?[/color]

                  Using a variable twice in an expression is ok. *Modifying* a variable
                  twice in an expression is not. More precisely, modifying a variable
                  twice without an intervening sequence point invokes undefined
                  behavior. (Many expressions don't have sequence points within them.)
                  [color=blue]
                  > question 3.4
                  >
                  > "Operator precedence and explicit parentheses impose only a partial
                  > ordering on the evaluation of an expression."
                  > I dont quite understand this, If I write
                  >
                  > ((3 + 4) * 2)
                  >
                  > in my mind, the paretheses causes the following evaluation
                  >
                  > (3 + 2) => 5 then
                  > (5 * 2) => 10
                  >
                  > because the second statement can not be evaluated before the first is
                  > evaluated. So does the fact contradict this assumption?[/color]

                  Given ((3 + 4) * 2), the compiler is free to replace the entire
                  expression with a literal 14, so the order of evaluation isn't
                  visible.

                  But consider the case where the operands are function calls rather than
                  integer constants:

                  ((f3() + f4()) * f2())

                  The addition cannot be performed until after both f3() and f4() have
                  been called, because until then there's nothing for it to add.
                  Likewise, the multiplication cannot be performed until all three
                  functions have been called.

                  *But*, there is no defined ordering on the function calls themselves.
                  Regardless of operator precedence and parentheses, the function calls
                  could occur in any order:

                  f3(), f4(), f2()
                  f3(), f2(), f4()
                  f4(), f3(), f2()
                  f4(), f2(), f3()
                  f2(), f3(), f4()
                  f2(), f4(), f3()

                  The compiler can generate code to call all three functions in any
                  arbitrary order, save the results, and then perform the addition and
                  multiplication. Precedence and parentheses only control which
                  operators take which operands.

                  This can be significant if the functions have side effects (such as
                  output).

                  The "+" and "*" operators themselves have no side effects, but
                  consider the case of passing function call results to functions.
                  Replacing "+" by add() and "*" by mult():

                  mult(add(f3(), f4()), f2())

                  Here we have 5 function calls, but not all orderings are allowed,
                  since a function can't be called until its arguments are available.
                  The ordering constraints are:

                  f3() and f4() must be called before add()
                  add() and f2() must be called before mult()

                  This reduces the 120 (5 factorial) possible orderings to some smaller
                  number that I'm too lazy to figure out.

                  And I'm sure that's a *lot* more than you wanted to know.

                  --
                  Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                  San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                  We must do something. This is something. Therefore, we must do this.

                  Comment

                  • Charles Richmond

                    #24
                    Re: i++ * i++

                    Lew Pitcher wrote:[color=blue]
                    >
                    > -----BEGIN PGP SIGNED MESSAGE-----
                    > Hash: SHA1
                    >
                    > rohit wrote:[color=green]
                    > > #include <stdio.h>
                    > > #define PRODUCT(x) (x*x)
                    > >
                    > > int main()
                    > > {
                    > >
                    > > int i =3,j,k;
                    > > j = PRODUCT(i++);
                    > > k = PRODUCT(++i);
                    > >
                    > > printf("\n%d %d", j,k);
                    > >
                    > > return (0);
                    > > }
                    > >
                    > > -----------------------------------------------------------
                    > > The output is 9 and 49
                    > >
                    > > shouldn't the answer be 12 and 20?[/color]
                    >
                    > Nope. Because your code modifies an object twice between sequence
                    > points, you've strayed into the realm of "undefined behaviour", and
                    > /any/ answer is the "proper" answer.
                    >[/color]
                    IMHO it is too bad that the C standard can *not* specify that
                    when you modiy an object twice between sequence points...
                    a hand will come out of the screen and bitch-slap you.


                    --
                    +----------------------------------------------------------------+
                    | Charles and Francis Richmond richmond at plano dot net |
                    +----------------------------------------------------------------+

                    Comment

                    • Richard Bos

                      #25
                      Re: i++ * i++

                      arnold <arnold@example .net> wrote:
                      [color=blue]
                      > Chris Smith wrote:
                      >[color=green]
                      > > No, that's not it. It means "increment i" and also "the result of the
                      > > expression is the value that i had before being incremented". This
                      > > implies nothing at all about the order in which the increment or the use
                      > > of the value of the expression occur. It's entirely possible that the
                      > > compiler will generate code to store off the value of i, increment i
                      > > immediately, and then use that temporary value in another expression.
                      > > Or alternatively, generate code to increment i first, then make a copy
                      > > and subtract one from the copy. Or, alternatively, generate a machine
                      > > code instruction that performs the increment simultaneously with using
                      > > the original value in another expression.[/color]
                      >
                      > ok, see. so logically, within one expression, that would mean
                      >
                      > use value of i, in the next expression containing i use i+1[/color]

                      No. For _correct_ code, it could be expressed somewhat inaccurately as
                      something like

                      use value of i, starting with the next _full_ expression containing i
                      use i+1

                      However...
                      [color=blue]
                      > let me check if I understand, an expression of the form
                      >
                      > (((i_1++ - b) / 3) + i_2++) + c-i_3)
                      >
                      > would then mean
                      >
                      > i_1 expression: use value of i_1,
                      > i_2 expression: use value of i_1+1,
                      > i_3 expression: use value of i_1+2[/color]

                      i_1, i_2 and i_3 are not full expressions, they are sub-expressions of
                      the whole line.
                      Actually, "full expression" is misleading. The real sticking point is
                      "between sequence points". The end of a statement is a sequence point,
                      but so are some select operators such as the logical (&&, ||) and comma
                      operators, and the actual call of a function, _after_ all its operands
                      have been determined, and some others. The * operator, however, is not,
                      and neither is any of the operators in your line above.

                      The real meaning of i++ is

                      evaluate to the value of i, and as a side effect, increment i

                      and that of ++i is

                      evaluate to the value of i plus one, and as a side effect, increment i

                      In neither of these cases is there any guarantee about the order in
                      which the the evaluation and the side effect are performed; and all side
                      effects _may_ be done just after the previous sequence point (statement
                      start, logical operator) and they _may_ be done just before the next
                      sequence point (end of the statement, function call), or they may be
                      done as a left-to-right reading of the code would indicate, or they may
                      even be shoved off to a parallel processor and done at the same time as
                      the main value of the expression is calculated. Or worse.
                      [color=blue]
                      > But since the OP's expression uses macro it al changes and leads to
                      > undefined behaviour.[/color]

                      The macro _as such_ has nothing to do with it. The problem is that
                      _this_ macro, applied as it is, expands to

                      i++ * i++

                      and _that_ expression causes the undefined behaviour. It would do so if
                      it were entered straight into the code just as much as when it comes
                      from a macro.

                      Richard

                      Comment

                      • arnold

                        #26
                        Re: i++ * i++



                        Thanks, with your and Keiths replies I think I understand now.

                        cheers.

                        Comment

                        • Ravi Nakidi

                          #27
                          Re: i++ * i++

                          Hi Rohit,


                          Compiler always executing the program sequentially. But, macros having
                          some side effects. I think this is already known by u very well.
                          Without compiler permission it will change the values of the variable.

                          See how,

                          Compiler start execution from int i=3, on

                          then it comes to the j = PRODUCT(i++);

                          then this is as it is submitted to the macro then u'r macro became

                          #define PRODUCT(i++) (i++ * i++);

                          now i = 3, so 3++ * 3++
                          so 3*3 =9 now j became 9 but i will become 5 correct becuse i++ and i++
                          in macro;

                          Then it comes to the second k = PRODUCT(++i);

                          this is ++i * ++i correct i is already 4 then pre increament ++i then
                          i=6 and then ++i the i=7

                          then 7*7 =49

                          Correct.


                          Regards,
                          Ravi Nakidi,
                          S/w Engg

                          Comment

                          • arnold

                            #28
                            Re: i++ * i++

                            Keith Thompson wrote:
                            [color=blue]
                            > Given ((3 + 4) * 2), the compiler is free to replace the entire
                            > expression with a literal 14, so the order of evaluation isn't
                            > visible.[/color]

                            I understand. (So you know, my example was simplified as imagine an
                            expression where variables had the following values, i could have used
                            variable names, but for some reason I did not.
                            [color=blue]
                            > And I'm sure that's a *lot* more than you wanted to know.[/color]

                            No, it was exactly the explanation I was looking for.

                            arnold

                            Comment

                            • Chris Smith

                              #29
                              Re: i++ * i++

                              Ravi Nakidi <laviravi@gmail .com> wrote:[color=blue]
                              > Compiler start execution from int i=3, on
                              >
                              > then it comes to the j = PRODUCT(i++);
                              >
                              > then this is as it is submitted to the macro then u'r macro became
                              >
                              > #define PRODUCT(i++) (i++ * i++);
                              >
                              > now i = 3, so 3++ * 3++
                              > so 3*3 =9 now j became 9 but i will become 5 correct becuse i++ and i++
                              > in macro;
                              >
                              > Then it comes to the second k = PRODUCT(++i);
                              >
                              > this is ++i * ++i correct i is already 4 then pre increament ++i then
                              > i=6 and then ++i the i=7
                              >
                              > then 7*7 =49[/color]

                              That's certainly one of the infinite number of things that a conforming
                              compiler could generate from that code. However, it's no more correct
                              than the compiler generating generating an answer of -1234567890. There
                              are multiple assignments between sequence points. The result is
                              undefined. Period. That's really all there is to it.

                              --

                              The Easiest Way To Train Anyone... Anywhere.

                              Chris Smith - Lead Software Developer/Technical Trainer
                              MindIQ Corporation

                              Comment

                              • Mark McIntyre

                                #30
                                Re: i++ * i++

                                On Thu, 16 Mar 2006 23:10:24 GMT, in comp.lang.c , Keith Thompson
                                <kst-u@mib.org> wrote:
                                [color=blue]
                                >Yes, but there are no sequence points between the evaluations of the
                                >arguments. This:
                                > func(i++, i++);
                                >invokes undefined behavior because it modifies i twice between
                                >sequence points (regardless of what happens inside func()).[/color]

                                You're right of course. FAQ 3.2
                                Mark McIntyre
                                --
                                "Debugging is twice as hard as writing the code in the first place.
                                Therefore, if you write the code as cleverly as possible, you are,
                                by definition, not smart enough to debug it."
                                --Brian Kernighan

                                Comment

                                Working...