i++ * i++

R

rohit

#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?

What are the steps the compiler takes to reach the above given output?
 
L

Lew Pitcher

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
#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);
}

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.
What are the steps the compiler takes to reach the above given output?

1) Flip Magic 8 Ball back and forth three times
2) Turn Magic 8 Ball face down
3) Read answer from Magic 8 Ball window

or not



- --

Lew Pitcher, IT Specialist, Corporate Technology Solutions,
Enterprise Technology Solutions, TD Bank Financial Group

(Opinions expressed here are my own, not my employer's)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEGYuBagVFX4UWr64RAgNlAKDZqIXvfF7lVMFMrR2VP4m68URgPQCgz7aN
dLkdF+Tl22Pt4hXN3e0yIyw=
=NM3n
-----END PGP SIGNATURE-----
 
T

Thomas Lumley

rohit said:
#include <stdio.h>
#define PRODUCT(x) (x*x)

This is asking for trouble: consider PRODUCT(2+2), which expands to
2+2*2+2,
ie 8 rather than 16, but that isn't what is causing this particular
problem.
int main()
{

int i =3,j,k;
j = PRODUCT(i++);

This is undefined behaviour: it expands to i++*i++
k = PRODUCT(++i);

printf("\n%d %d", j,k);

return (0);
}

-----------------------------------------------------------
The output is 9 and 49
Ok.

shouldn't the answer be 12 and 20?

No. It can be anything. Yes, anything.
What are the steps the compiler takes to reach the above given output?

Whatever it feels like.

Read the FAQ (starting with question 3.2, which is exactly this
question). (c-faq.com)
You might also find
http://www.eskimo.com/~scs/readings/undef.981105.html useful.

There is actually a perfectly sensible explanation for how the program
might have computed 9 and 49, but trying to second-guess undefined
behaviour is a bad idea.

-thomas
 
C

Chris Smith

rohit said:
#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);
}

For your compiler on your hardware platform, anyway.
shouldn't the answer be 12 and 20?

The answer is that multiple assignments between sequence points yield
undefined behavior.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
B

Ben C

#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?

What are the steps the compiler takes to reach the above given output?

See the FAQ, 3.1

http://c-faq.com/expr/index.html
 
S

Steve

When the compiler sees the i++ the value of i is not actually ever
incremented until after the current statement has executed. So when you
say i++ when i = 3 in that statement it is always 3 in that statement.
You increment the value twice since it says i++ * i++ only in the next
statement. With the ++i the value is incremented before the statement
starts so it sees a 5 from the above line then increments twice to 7 and
then preforms the PRODUCT.
 
R

Richard Bos

[ Do not top-post, please. ]
When the compiler sees the i++ the value of i is not actually ever
incremented until after the current statement has executed.

This is wrong. What happens when you execute i++ is this:
- the value returned is the value of i before this expression, _and_
- i is incremented.
In which order these are done is not defined; they could even be done in
parallel.
So when you
say i++ when i = 3 in that statement it is always 3 in that statement.

This, too, is wrong.

Richard
 
C

Chris Dollin

rohit said:
#include <stdio.h>
#define PRODUCT(x) (x*x)

Should be ((x)*(x)) - consider the argument `i + 1`.

Actually, more like "should be `int product(x) { return x*x; }`.
int main()
{

int i =3,j,k;
j = PRODUCT(i++);
BOOM.

k = PRODUCT(++i);

printf("\n%d %d", j,k);

return (0);
}

This a FAQ, so see the C FAQ, eg

http://www.faqs.org/faqs/C-faq/faq/
question 3.2
What are the steps the compiler takes to reach the above given output?

It compiles code for `i++ * i++` assuming that you know what you're
doing. So, at a guess, it multiples i (3) by i (still 3) to get 9.
The it increments i, possibly twice.

The it compiles code for `++i * ++i` ATYKWYD. At a guess, it increments
i, probably twice, then multiplies i (7) by i (still 7) to get 49.

The compiler-writer of course could do things differently. They could
keep a flag for each variable, "increment pending". Then `i++` compiles
as "get the value of i and set the flag", and ";" compiles as "increment
all variables with the flag set, and clear it"; and "++i" compiles as
"increment i, and return the new value". In that case, you'd
get the results 9 and 20.

Or they could compile `i++` as "if the flag is set, report a problem,
plant code to quit the program; otherwise, get the value of i and
set the flag."
 
S

Steve

This is short sighted because of a few other reasons but wrong is
extremely, just another way to interpret the actions the final result.
Thanks though for pointing it out.

Richard said:
[ Do not top-post, please. ]
When the compiler sees the i++ the value of i is not actually ever
incremented until after the current statement has executed.

This is wrong. What happens when you execute i++ is this:
- the value returned is the value of i before this expression, _and_
- i is incremented.
In which order these are done is not defined; they could even be done in
parallel.
So when you
say i++ when i = 3 in that statement it is always 3 in that statement.

This, too, is wrong.

Richard
 
K

Kenneth Brody

Steve wrote:

[Again, please don't top post. Top-posting corrected for this reply.]
Richard said:
[ Do not top-post, please. ]
#define PRODUCT(x) (x*x)
j = PRODUCT(i++);
k = PRODUCT(++i);
The output is 9 and 49

shouldn't the answer be 12 and 20?
When the compiler sees the i++ the value of i is not actually ever
incremented until after the current statement has executed.

This is wrong. What happens when you execute i++ is this:
- the value returned is the value of i before this expression, _and_
- i is incremented.
In which order these are done is not defined; they could even be done in
parallel.
So when you
say i++ when i = 3 in that statement it is always 3 in that statement.
This is short sighted because of a few other reasons but wrong is
extremely, just another way to interpret the actions the final result.
Thanks though for pointing it out.

No, your answer was wrong. Had you said "it appears that your particular
compiler, given the command line flags you specified, has generated code
which behaves as ...", you might have been "right". But your generalized
statement implying that "the meaning of post- and pre-increment is..." is
simply untrue.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
A

arnold

Richard said:
This is wrong. What happens when you execute i++ is this:
- the value returned is the value of i before this expression, _and_
- i is incremented.
In which order these are done is not defined; they could even be done in
parallel.

Could you explain? When you say "order is not defined" are you talking
about these two?

I allways thought that a statement like i++ meant

first use the value of i then increment it

since this is a macro does it change how it works or did i fundamentally
misunderstand.

arnold
 
A

Artie Gold

arnold said:
Could you explain? When you say "order is not defined" are you talking
about these two?
[some context restored]
I allways thought that a statement like i++ meant

first use the value of i then increment it

since this is a macro does it change how it works or did i fundamentally
misunderstand.
Well, it's not the individual applications of ++ (whether prefix or
postfix) that are a problem, it's the fact that multiple side effects
occur without an intervening sequence point.

Consider the expansions of the expressions above:

PRODUCT(i++) => i++ * i++ and
PRODUCT(++i) => ++i * ++i

in both cases the variable `i' is side affected (did I really say `side
affected'?) twice with no intervening sequence point; since the order in
which things occur is specifically undefined, the overall behavior is
undefined as well.

The C standard, *could*, of course, have defined the order. But it
doesn't. [And that's not likely to change.]

HTH,
--ag
 
C

Chris Smith

arnold said:
I allways thought that a statement like i++ meant

first use the value of i then increment it

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.

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.
since this is a macro does it change how it works or did i fundamentally
misunderstand.

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.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
A

arnold

Chris said:
> 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.

Chris, it wasn't me, it was this other guy called rohit, the OP:)

> 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.

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?

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?
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.

ok, see. so logically, within one expression, that would mean

use value of i, in the next expression containing i use i+1

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


But since the OP's expression uses macro it al changes and leads to
undefined behaviour.

If this is correct the I think I understand,

arnold
 
M

Mark McIntyre

The reason i++ is used twice is because its a macro?

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

Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
is literally replaced by i++ * i++
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?

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
 
K

Keith Thompson

Mark McIntyre said:
Not really - its used twice because thats what the OP programmed for.


Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
is literally replaced by i++ * i++


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.

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()).
 
K

Keith Thompson

arnold said:
Chris, it wasn't me, it was this other guy called rohit, the OP:)



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?

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.
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?

Mistaken; see my other response in this thread.
 
A

arnold

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.
> Yes, a macro is a literal text replacement. In this case PRODUCT(i++)
> is literally replaced by i++ * i++

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)

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.

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,501
Latest member
Ledmyplace

Latest Threads

Top