a question

  • Thread starter c/c++ programming lover
  • Start date
C

c/c++ programming lover

I'm sorry.Last time i made a mistake.The modified question is :
#include<stdio.h>
int main()
{
int a=5;
printf("%d",++a*++a);
return 0;
}
the result is 49;
why?very thanks.
 
M

Michael DOUBEZ

c/c++ programming lover a écrit :
I'm sorry.Last time i made a mistake.The modified question is :
#include<stdio.h>
int main()
{
int a=5;
printf("%d",++a*++a);
return 0;
}
the result is 49;
why?very thanks.

Perhaps because it full moon tonight.
Or more probably because if you had had 42 as an answer you wouldn't
have learned about "sequence point"; a sign from fate perhaps.
 
J

Juha Nieminen

c/c++ programming lover said:
I'm sorry.Last time i made a mistake.The modified question is :
#include<stdio.h>
int main()
{
int a=5;
printf("%d",++a*++a);
return 0;
}
the result is 49;
why?very thanks.

What do you expect should happen? The standard only says that the
variable is incremented before usage. It doesn't specify exactly at
which point it's incremented. The compiler is perfectly allowed to
convert the printf call above to code equivalent to:

++a; ++a; printf("%d", a*a);

The compiler is completely inside the bounds given by the standard
when doing that: It's incrementing the variable before its usage.

Of course you can't trust *all* compilers interpret the situation like
that, so the result can very well vary between compilers (yet all of
them are nevertheless standard-compliant).
 
J

James Kanze

What do you expect should happen? The standard only says that
the variable is incremented before usage.

No it doesn't. As Pete has already said, it's irrelevant here,
since the code has undefined behavior, but all the standard says
is that the variable will be incremented before the next
sequence point. Even if there wasn't undefined behavior.
 
J

Juha Nieminen

James said:
No it doesn't. As Pete has already said, it's irrelevant here,
since the code has undefined behavior, but all the standard says
is that the variable will be incremented before the next
sequence point. Even if there wasn't undefined behavior.

But (as far as I know) jumping to a function call (in this case
printf) marks a sequence point, so the variable must have been
incremented before the code jumps to the printf function.

I think it's thus pretty unambiguous that the variable a will have
been incremented twice before the printf call is executed, and thus will
have a value of 7. It's also pretty unambiguous that the value 5 cannot
be part of the multiplication because the very definition of the
prefix++ operator makes that impossible. The only thing which in
practice is not guaranteed in "++a*++a" is in which order the variable a
is incremented and its value used in with the binary operator*.

Thus, in practice, only four things can conceivably happen:

1) The first "++a" is executed first, incrementing the value of a, and
the value of that expression will be 6. After this the second "++a" is
executed and this results in 7 as the second operand, and thus the
result will be 42.

2) The reverse happens: The second "++a" is executed first, its value
taken, and then the first one. The result of the multiplication will
still be the same.

3) Both "++a" operators are executed first, after which the value of a
(ie. 7) is used as the parameters of the multiplication, which results
in 49.

4) The compiler decides that the value of the expression "++a" is 6, and
thus uses 6 as the value for both operands of the operator*. Thus the
result of the multiplication will be 36. (Although I would say that this
case is the most unlikely of the four in practice.)

I see no logical reason why any compiler would produce anything else
than something that prints 36, 42 or 49.

But of course this is just theoretizing about compiler behavior in
practice. It's not like you should ever use anything like "++a*++a".
 
J

James Kanze

But (as far as I know) jumping to a function call (in this
case printf) marks a sequence point, so the variable must have
been incremented before the code jumps to the printf function.

Yes. Calling a function or returning from one are sequence
points.
I think it's thus pretty unambiguous that the variable a will
have been incremented twice before the printf call is
executed, and thus will have a value of 7.

Not in this case, because the standard says that there is
undefined behavior.
It's also pretty unambiguous that the value 5 cannot be part
of the multiplication because the very definition of the
prefix++ operator makes that impossible.

Not in this case, because the standard says that there is
undefined behavior. Also because there is no sequence point
between the incrementation and the multiplication, so the update
to the variable need not have taken place. But the undefined
behavior trumps.
The only thing which in practice is not guaranteed in
"++a*++a" is in which order the variable a is incremented and
its value used in with the binary operator*.

Nothing is guaranteed in practice, because there is undefined
behavior. Just what part of undefined don't you understand?
Thus, in practice, only four things can conceivably happen:
1) The first "++a" is executed first, incrementing the value of a, and
the value of that expression will be 6. After this the second "++a" is
executed and this results in 7 as the second operand, and thus the
result will be 42.
2) The reverse happens: The second "++a" is executed first, its value
taken, and then the first one. The result of the multiplication will
still be the same.
3) Both "++a" operators are executed first, after which the value of a
(ie. 7) is used as the parameters of the multiplication, which results
4) The compiler decides that the value of the expression "++a" is 6, and
thus uses 6 as the value for both operands of the operator*. Thus the
result of the multiplication will be 36. (Although I would say that this
case is the most unlikely of the four in practice.)

That's the only one I've actually seen (but I've not looked
much). In C, with the Microsoft compiler.

Not actually seen by me, but I have heard it reported that on
certain machines, such expressions result in reading and writing
from the same address at the same time (on a machine with dual
port memory), which results in the memory freezing up, and the
operations never finishing. (It sounds a bit strange from what
I know of hardware, but such machines have purportedly existed.)

All of which really isn't relevant, because the expression
contains undefined behavior. Since the C90 standard, at least.
(At least two people, including myself, have argued that this
should be fixed. But there's been absolutely no support for it
in the committee.)
I see no logical reason why any compiler would produce
anything else than something that prints 36, 42 or 49.

What part of undefined don't you understand? There's no
requirement that undefined behavior be logical.
But of course this is just theoretizing about compiler
behavior in practice. It's not like you should ever use
anything like "++a*++a".

Agreed. In practice, even if it were only unspecified, what's
the use of an expression which produces random results.
 
J

Juha Nieminen

James said:
Nothing is guaranteed in practice, because there is undefined
behavior. Just what part of undefined don't you understand?

The part where a compiler would encounter a "++a" and do something
completely different than incrementing the value of that variable for
the simple reason that later in the same expression there's another
"++a". Why would a compiler deliberately behave differently upon a "++a"
expression if it happens to appear more than once in the same expression?

Granted, you can't guarantee *how* the compiler behaves when it
encounters a "++a" (more precisely, exactly at which point the
incrementation and using the new value happen). However, my point is
that I don't understand why a compiler would deliberately act
*differently* from that behavior if there's another "++a" in the same
expression. Why would it do that? Just to annoy? It would make the
compiler more complicated and for what reason?
 
S

Sana

  The part where a compiler would encounter a "++a" and do something
completely different than incrementing the value of that variable for
the simple reason that later in the same expression there's another
"++a". Why would a compiler deliberately behave differently upon a "++a"
expression if it happens to appear more than once in the same expression?

let's come up with some pseudo assembler:

int a = 5;
++a * ++a;
the assembler might look like this:

1. load first operand in register R1
2. load second operand in register R2
3. increment R1
4. increment R2
5. save R1
6. save R2
7. multiply R1 and R2
8. use the result for the function call

/sana
 
J

James Kanze

The part where a compiler would encounter a "++a" and do
something completely different than incrementing the value of
that variable for the simple reason that later in the same
expression there's another "++a". Why would a compiler
deliberately behave differently upon a "++a" expression if it
happens to appear more than once in the same expression?

I don't understand your point. The compiler "knows" that the
two ++ affect different objects, since otherwise the code would
be illegal. So it can optimize in consequence. The results of
this optimization can sometimes be surprising.

But what any one compiler does is really irrelevant. The
compiler is free to do whatever happens to be convenient. (One
obvious way of generating ++x is to load x into a register,
increment the register, and not write the results back until
necessary. I expect that with a lot of compilers, when
optimizing is turned up, one of the increments gets lost; i.e.
if a were 5 before the expression, it would only be 6 after.)
Granted, you can't guarantee *how* the compiler behaves when
it encounters a "++a" (more precisely, exactly at which point
the incrementation and using the new value happen). However,
my point is that I don't understand why a compiler would
deliberately act *differently* from that behavior if there's
another "++a" in the same expression. Why would it do that?
Just to annoy? It would make the compiler more complicated and
for what reason?

It doesn't act differently. But take a more realistic example,
where the expression involves pointers, e.g.:
++ *p * ++ *q
Having seen that expression, the compiler now knows that p and
q cannot refer to the same object, i.e. their is no aliasing.
Which is often important information for an optimizer.

Of course, the consideration which caused the rule to be
introduced was more fundamental. On some architectures,
scheduling of writes and reads could overlap, and it was up to
the compiler to keep them separate, and scheduling a write and a
read at the same address could cause the memory to hand, never
resonding (apparently---I've seen machines with the scheduling
issues, but never one that would hang on multiple accesses to
the same address, but no problem when accessing different
addresses).
 
J

James Kanze

[...]
Suppose the compiler decides to do the increments in parallel,
e.g. using one of the parallel-add instructions on the IBM
Cell processors. Could you then have simultaneous writes to
the same address, and could this cause a bus error?

Aha. You have a concrete example of this problem. I'd heard
about it, but only vaguely, and wasn't sure whether it was real,
or only purported. It's nice to have a real concrete instance.
 
S

Sana

Sanawrote:
let's come up with some pseudo assembler:
int a = 5;
++a * ++a;
the assembler might look like this:
1. load first operand in register R1
2. load second operand in register R2
3. increment R1
4. increment R2
5. save R1
6. save R2
7. multiply R1 and R2
8. use the result for the function call

What's the point of this?  The assembler might look differently:

1. load first operand in register R1
2. increment R1
3. save R1
4. load [the same, just incremented] operand in register R1
6. increment R1
6. save R1
8. multiply R1 and R1
9. use the result for the function call

The behaviour is *undefined*.  Any attempt to define it is simply
pointless.  The language Standard imposes *no requirements*.  No
matter what you can come up with, it would be *OK*.  Just like
any other sequence of steps anybody else can come up with.  Like

1. send e-mail to your boss calling him/her a bastard and
   telling him/her that you quit
2. format the hard drive

Exactly! It seemed that the OP was thinking of a sequence as the one
you posted. I was trying to show him that the sequence may be
different, leading to a different result.
Totally agree, changing a variable twice without a sequence point in
between is undefined behavior.

/sana
 

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

Forum statistics

Threads
474,167
Messages
2,570,910
Members
47,453
Latest member
MadelinePh

Latest Threads

Top