5
int main(void)
{
    int i = 0;
    i = ++i % 3;
    return 0;
}

I compile it like this:

$ gcc -Wall main.c -o main
main.c: In function ‘main’:
main.c:4: warning: operation on ‘i’ may be undefined

Why does the compiler say i may be undefined?

vv1133
  • 739
  • 1
  • 8
  • 21
  • 2
    The *operation* is undefined, not `i` itself. I.e. it's Undefined Behaviour. Don't do it. – Paul R Oct 24 '11 at 14:35
  • @Paul R why do you think operation is undefined ? ++i increments i to 1 and modulo opeartor 1 with 3 gives 1 as result. doesnt that work ? – niko Oct 24 '11 at 14:39
  • 1
    @niko: See my answer and http://www.catb.org/jargon/html/N/nasal-demons.html – Fred Larson Oct 24 '11 at 14:42
  • @niko: see Fred's answer below and the links in his answer for further explanation of sequence points etc – Paul R Oct 24 '11 at 14:45
  • I accept this wierdo implementation of compiler and I know its undefined but never found some links. Thanks for your help – niko Oct 24 '11 at 14:45
  • 2
    @niko: I'd hardly call gcc a "weirdo implementation". Seems to be pretty well-respected to me, and as far as this issue is concerned it's completely standards compliant. – Fred Larson Oct 24 '11 at 15:04
  • @niko - see the latest draft of the C language standard at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf, section 6.5. Expressions of the type in the OP are explicitly called out as undefined behavior. – John Bode Oct 24 '11 at 18:07

3 Answers3

11

Because you are modifying the value of i twice without an intervening sequence point. It's undefined behavior.

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
6

In standardese, it's undefined behaviour because i is modified twice without an intervening sequence point.

i = ++i % 3;

But that's not really the point. The real point is: why on earth would anyone write such code?!

What is the value that you want i to have? If you're assigning a whole new value into i with i = ..., what effect are you trying to achieve with ++i? If this were parallel-universe-C in which code like this actually had meaning, then -- in the best case -- the incremented i is immediately replaced with the whole new value assigned. So why not just write it as

i = (i+1) % 3;

which is also correct in C-as-we-know-it.

John Marshall
  • 6,815
  • 1
  • 28
  • 38
4

As others have pointed out, the behavior is undefined:

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.72) Furthermore, the prior value shall be read only to determine the value to be stored.73)
...
72) A floating-point status flag is not an object and can be set more than once within an expression. 73) This paragraph renders undefined statement expressions such as
    i = ++i + 1;
    a[i++] = i;
while allowing
    i = i + 1;
    a[i] = i;

The expression i = ++i % 3 attempts to modify the value contained in i twice before the next sequence point (in this case, the ; ending the statement), once by evaluating ++i, and once by evaluating the larger assignment expression.

Now, why would this be a problem? After all, C# and Java can handle these expressions just fine.

The problem is that, with few exceptions, C doesn't guarantee that operands in an expression are evaluated in any particular order, or that the side effects of an expression will be applied immediately after the expression is evaluated (unlike C# and Java, which do make those guarantees). For example, the expression ++i has a result (i + 1) and a side effect (increment the value stored in i); however, the side effect can be deferred until the larger expression has been evaluated. IOW, the following sequence of actions is allowed:

    t0 = i + 1
    t1 = t0 % 3
    i = t1
    i = i + 1

Oopsie. Not what we wanted.

This was a deliberate design decision; the idea is that it allows compilers to reorder evaluations in an optimal manner (by taking advantage of a value that's already in a register, say). The downside is that certain combinations of expressions will have unpredictable results.

John Bode
  • 119,563
  • 19
  • 122
  • 198