views:

1540

answers:

4
int main(int argc, char ** argv)
{

   int i = 0;
   i = i++ + ++i;
   printf("%d\n", i); // 3

   i = 1;
   i = (i++);
   printf("%d\n", i); // 2 Should be 1, no ?

   volatile int u = 0;
   u = u++ + ++u;
   printf("%d\n", u); // 1

   u = 1;
   u = (u++);
   printf("%d\n", u); // 2 Should also be one, no ?

   register int v = 0;
   v = v++ + ++v;
   printf("%d\n", v); // 3 (Should be the same as u ?)
}
+25  A: 

Sigh. Why are these "issues"? The language clearly says that certain things lead to undefined behavior. There is no problem, there is no "should" involved. If the undefined behavior changes when one of the involved variables is declared volatile, that doesn't prove or change anything. It is undefined, you cannot reason about the behavior.

Your most interesting-loooking example, the one with

u = (u++);

is a (wiki) text-book example of undefined behavior (see Wikipedia's entry on sequence points).

unwind
+max_int. Use statements which the language standard actually tells you what they will do. Do not use undefined behaviour and then wonder what's going on.
Daniel Daranas
I knew it was undefined, (The idea of seing this code in production frighten me :)) but I tried to understand what was the reason for these results. Especially why u = u++ incremented u. In java for example:u = u++ returns 0 as (my brain) expected :) Thanks for the sequence points links BTW.
PiX
Obviously because of the brackets around the u++ the compiler has decided to incerement u and then return it.As it is undefined behaviuor in C this is ligitimate. A different compiler or even a different machine and the same one may give a different answer. I do not know java, but perhaps the behaviour is clearly defined.
ChrisBD
@PiX: Things are undefined for a number of possible reasons. These include: there is no clear "right result", different machine architectures would strongly favour different results, existing practice is not consistent, or beyond the scope of the standard (e.g. what filenames are valid).
Richard
+6  A: 

This is related to something called sequence points.

You can read more about it here basically what you have written is not allowed and has undefined behavior.

Anders K.
+3  A: 

I think the relevant parts of the C99 standard are 6.5 Expressions, §2

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.

and 6.5.16 Assignment operators, §4:

The order of evaluation of the operands is unspecified. If an attempt is made to modify the result of an assignment operator or to access it after the next sequence point, the behavior is undefined.

Christoph
+2  A: 

Just compile and disassemble your line of code, if you are so inclined to know how exactly it is you get what you are getting.

This is what I get on my machine:

$ cat evil.c
void evil(){
  int i = 0;
  i+= i++ + ++i;
}
$ gcc evil.c -c -o evil.bin
$ gdb evil.bin
(gdb) disassemble evil
Dump of assembler code for function evil:
   0x00000000 <+0>:   push   %ebp
   0x00000001 <+1>:   mov    %esp,%ebp
   0x00000003 <+3>:   sub    $0x10,%esp
   0x00000006 <+6>:   movl   $0x0,-0x4(%ebp)
   0x0000000d <+13>:  addl   $0x1,-0x4(%ebp)
   0x00000011 <+17>:  mov    -0x4(%ebp),%eax
   0x00000014 <+20>:  add    %eax,%eax
   0x00000016 <+22>:  add    %eax,-0x4(%ebp)
   0x00000019 <+25>:  addl   $0x1,-0x4(%ebp)
   0x0000001d <+29>:  leave  
   0x0000001e <+30>:  ret    
End of assembler dump.
badp
+1 for illustrating the concept of actually understanding the machine underlying the construct.
JUST MY correct OPINION