0

So just for fun, I have this code snippet:

#include <stdio.h>
main()
{
 int i;
 int a;
 i = 17;
 //scanf("%d", &i);
 a = (i+=5) * (i-=3);
 printf("a is %d, i is %d\n", a, i);
}

In C specifications, it says the order of operands evaluation is undefined, so I was expecting to see either 22 * 19, or 19 * 14. However, the result is 19 * 19:

~ $ gcc a.c
~ $ ./a.out
a is 361, i is 19

I thought about it, and the only explanation I could come up with is that the compiler did a 'delayed' evaluation on (i+=5)'s value, and it thought that (i+=5)'s value is just value of i. same for (i-=3).

However, if I uncomment the scanf():

#include <stdio.h>
main()
{
 int i;
 int a;
 i = 17;
 scanf("%d", &i);
 a = (i+=5) * (i-=3);
 printf("a is %d, i is %d\n", a, i);
}

Now I input 17 at prompt:

~ $ gcc a.c
~ $ ./a.out
17
a is 418, i is 19

Why does it show different behavior?

exexzian
  • 7,782
  • 6
  • 41
  • 52
  • 3
    Why are you surprised that undefined behaviour results in unpredictable behaviour? – congusbongus Mar 07 '13 at 02:25
  • It is undefined. It can print 0 for all gcc cares. – carlosdc Mar 07 '13 at 02:25
  • The behavior is different precisely because said behavior is **undefined**, as you already noted. – Code-Apprentice Mar 07 '13 at 02:28
  • 2
    I don't agree with the downvote. This person made an effort to investigate behaviour that they didn't understand, explain it clearly and ask a question. Don't chastise them for not understanding the scope of "undefined behaviour". Note that they expected the order of evaluation to be undefined, but not the entire operation. – paddy Mar 07 '13 at 02:31
  • If you're having a stressful day, sometimes it's best to take a break from commenting on StackOverflow. – paddy Mar 07 '13 at 02:56
  • @paddy: It is always a waste of time when a question has the general theme: "I know that this is undefined, but why isn't it doing what I expect?" – carlosdc Mar 07 '13 at 03:41
  • @carlosdc That is *not* the general theme of the question. The author stated that the *order* in which two operations would be evaluated was undefined, but fully expected the evaluation of those operations to be defined. I would expect a little more patience and less arrogance towards others, especially those who are new to StackOverflow. This person is trying to explore the C language and might consider participating in the StackOverflow community if they don't already think we're a bunch of pricks. It's not fair to discourage them from either of these things. How about a little courtesy? – paddy Mar 07 '13 at 03:57
  • @paddy: I honestly feel that in this situation I have not acted like a prick or a jerk. I also feel like I'm not holding the OP back in any way whatsoever. Let me also point out that even -Wall catches the undefined behavior. The OP knows he's in hot water with respect to the standard. What you bring up is a mere technicality. – carlosdc Mar 07 '13 at 04:34
  • @carlosdc My gripe was not really directed at you, but I responded to your defence of those who chose not to respond constructively. There is a tendency for this community to welcome new users by berating them for being in a position that most of us have probably been in at some point in our programming lifetimes. This person made comprehensive tests and puzzled over the results before asking a question. It did not occur to them that a fundamental assumption was incorrect. That's completely different to someone else who, having made no personal effort, might come here and ask for assistance. – paddy Mar 07 '13 at 08:32
  • @paddy, thanks for the support. I think that I'm a very experienced C programmer, and I always try my best before I ask things. However, majority of people think the other way. It's ok. It's my pleasure to know you. – flying tuzi Mar 08 '13 at 00:56

2 Answers2

5

It's Undefined Behavior. The C standard says that you're not allowed to modify the same object (i in this case) more than once between two sequence points (the semicolons before and after the statement, in this case).

Undefined Behavior means anything can happen. It can appear to work correctly. It can give the wrong answer. It can crash your process. It can erase your hard drive. Or it can even set your CPU on fire. These are all allowed behaviors according to the language standard.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
3

Probably the main difference is that, in your first case, i can be predicted during it's whole lifetime, so the optimizer precomputes it and replaces the variable with a constant value.

In your second example, the scanf makes that optimization impossible. The compiler can't know in advance what will be the value for i and does what you expected, which is undefined by the standard.

Diego Sánchez
  • 539
  • 2
  • 12