0

can someone explain to me why this code prints the decremented amount? Since (4 <= 3) is false, shouldn't it proceed to print "Hi"?

int main()
{
    int amount = 4;

    if((amount%5) <= (--amount))
        printf("%d", amount);
    else
        printf("Hi");
}
Newbie
  • 23
  • 1
  • Hello undefined behavior... – Retired Ninja May 05 '18 at 01:03
  • I don't think the question should have been downvoted. The person is obviously new to programming and is learning. It was an honest mistake for the person and just as @SteveSummit put it: *You might think the code has to be evaluated left-to-right... But that's not the way it works.* – Haris Nadeem May 05 '18 at 01:08

1 Answers1

3

Turns out this code is undefined. You've got the expression

(amount%5) <= (--amount)

But the key question is, does the amount%5 part use the old value of amount, or the new, after being decremented by the --amount part? And the answer is: We have no idea. There's no way to tell. There's no rule in the C language to tell us.

You might think the code has to be evaluated left-to-right, that the amount%5 part has to happen first, before the --amount part has a chance to happen. But that's not the way it works. Since it's undefined, anything could happen.

If it's evaluated more or less left-to-right, then we have

if(amount%5 <= --amount)

which evaluates to

if(4%5 <= --amount)

which evaluates to

if(4 <= --amount)

which evaluates to

if(4 <= 3)

which is false, so you might expect it to print "Hi". But, if it's evaluated more or less right-to-left, it's

if(amount%5 <= 3)

which evaluates to

if(3%5 <= 3)

which evaluates to

if(3 <= 3)

which is true.

(You'll notice that I have removed some extra parentheses, since they don't do anything.)

I hasten to add that these are not the only two possibilities. The rules say that once an expression is undefined, literally anything can happen -- the behavior doesn't have to be anything we might consider "reasonable" at all.

So why is it undefined? In this case it's because you have a variable -- amount -- which appears twice in the expression, and where one of those appearances is a modification (the --amount part), and where the other one uses the variable's value. The C Standard explicitly tells us that in this case (a) we can't tell whether the use of amount uses the old or the modified value, and furthermore that (b) this flaw in the expression -- this simultaneous modification and use -- renders the whole expression (and actually the whole program it's in) undefined.

So how do you fix it? The answer is simple, and it's the punchline of an old joke: Don't do that. Don't write expressions where a single variable (or other object) is both modified and used. It's fine to write --amount, just don't do it in an expression that's also using the value of the variable amount somewhere else.

Questions like this come up often. The canonical SO answers, which others are already redirecting you to, are collected under the question Why are these constructs (using ++) undefined behavior in C?. There's more I could say about the rules concerning undefined expressions, but you can find those details over at that question.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103