Is this a bug in clang?

Hello,

Is this a bug in clang, or a bug in my thinking?

/Joe Armstrong

/*

When I compile the following program I get different answers in clang and gcc.

  $ gcc bug2.c
  $ ./a.out
  j = 40
  $ clang bug2.c
  $ ./a.out
  j = 41

  I think the correct answer is 41. If my understanding of C is correct
  (which, or course, it might not be) the incremented value of i++ is
  first made available at the next sequence point, which is after the
  ';' at the end of the offending statment statement.

*/

int printf(const char * format, ...);

int main()
{
  int i, j;
  i = 10;
  j = i++ + 20 + i;
  printf("j = %d\n",j);
  return(0);
}

..

   I think the correct answer is 41. If my understanding of C is correct
   (which, or course, it might not be) the incremented value of i++ is
   first made available at the next sequence point, which is after the
   ';' at the end of the offending statment statement.

...

   j = i++ + 20 + i;

It is not a bug; you are relying on undefined behavior. Since the +
operator is commutative, the compiler is free to rearrange your
statement to e.g:

j = i + 20 + i++;

or any other possible permutation, all in the name of optimization.
Using different compilers, or even just different architectures or
compile flags, can lead to different results here.

In short, don't do this. :slight_smile:

Hi Joe

Hello,

Is this a bug in clang, or a bug in my thinking?

/Joe Armstrong

When I compile the following program I get different answers in clang and gcc.

int printf(const char * format, ...);

Nitpick: you shouldn't do that. Now you have a potential mismatch
between whet you compile and what you link to.

int main()
{
int i, j;
i = 10;
j = i++ + 20 + i;
printf("j = %d\n",j);
return(0);
}

$ gcc bug2.c
$ ./a.out
j = 40
$ clang bug2.c
$ ./a.out
j = 41

I think the correct answer is 41. If my understanding of C is correct
(which, or course, it might not be) the incremented value of i++ is
first made available at the next sequence point, which is after the
';' at the end of the offending statement statement.

There is no such guarantee. From the C99 standard,

5.1.2.3 Program execution:
} 2 ... At certain specified points in the execution sequence called
sequence points, all side effects
} of previous evaluations shall be complete and no side effects of
subsequent evaluations
} shall have taken place.

The side effect is made available _no_later_ than the sequence point.
There is no guarantee that it would not be made available earlier.

An example from the standard:

#include <stdio.h>
int sum;
char *p;
/* ... */
sum = sum * 10 - ’0’ + (*p++ = getchar());

the expression statement is grouped as if it were written as

sum = (((sum * 10) - ’0’) + ((*(p++)) = (getchar())));

but the actual increment of p can occur at any time between the
previous sequence point and the next
sequence point (the ;), and the call to getchar can occur at any point
prior to the need of its returned
value.
/quote

Also,

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 accessed only to determine the value to be stored.60)

Footnote 60:
} This paragraph renders undefined statement expressions such as
} i = ++i + 1;
} a[i++] = i;
} while allowing
} i = i + 1;
} a[i] = i;

If you are lucky, the behavior of your program is unspecified (each
implementation is required to behave consistently with itself, which
is why GCC and clang are allowed to produce different results).

If not, you invoked the dreaded undefined behavior.

Csaba