-1

I had been going over a few tricky and unusual behaviour that C code snippets produce, and I came across one that resulted an unusual output.

int main()
{
    int i=3;
    printf("%d%d%d", i, ++i, i++);
    return 0;
}

I thought this would have resulted in 344, but the output was 553.

I searched for the reason and apparently it's because of undefined behaviour of certain statements, particularly if there are multiple changes done to the same variable in a single statement.

However, how do you predict what the output would be? And how is 553 computed and justified as the answer to the above code snippet?

There might be an answer somewhere on SO, but I didn't know what to search for exactly. Thanks.

thegravity
  • 100
  • 2
  • 7
  • 2
    `However, how do you predict what the output would be?` don't predict the undefined behaviour. – kiran Biradar Dec 02 '18 at 15:07
  • The thing about this not being defined is that you *can't* reliably predict it. – StoryTeller - Unslander Monica Dec 02 '18 at 15:08
  • If you want to predict its behaviour you should take a look to the assemly that is produced – Leonardo Silvagni Dec 02 '18 at 15:21
  • @LeonardoSilvagni thank you, yes, answers on other questions suggested the same. Also, I found this question on a sample-test; which gives that if we can't reliably predict/justify the output, how come such questions are so common in interview tests? – thegravity Dec 02 '18 at 15:28
  • 2
    Such questions are so common because writing code with undefined behavior causes bugs, and avoiding writing such code requires knowledge about the rules of C, so the employers want to test whether you know the relevant rules. – Eric Postpischil Dec 02 '18 at 15:32
  • @EricPostpischil I'd understand that if it would be asked in a face to face interview to know 'why' the candidate has answered what he has answered. But what if the question is a part of an online test with the format: "1. Predict the output (a) option1 (b).. (c)... (d)...". Also, thank you, your comments have helped a lot in understanding C behaviour! – thegravity Dec 02 '18 at 15:38

1 Answers1

0

The problem here is the order at which arguments to a function call are evaluated, the specific compiler can decide in what order it sees the evaluation as reasonable. So depending on that you could have different outcomes depending on various factors.

Note that generally the evaluation of arguments is unsequenced and may vary depending on platform, compiler, or many other factors.

However, how do you predict what the output would be? And how is 553 computed and justified as the answer to the above code snippet?

You cannot predict this behavior. Its generally best not to have undefined behavior change the outcome of your code. This can be accomplished by dividing your code into multiple declarations:

int i = 3;
int a = ++i;
int b = i++;
printf("%d%d%d", i, a, b);

This way you can predict the outcome properly as you can see the order of evaluation correctly without relying on the compilers resulting evaluation order.

Minn
  • 5,688
  • 2
  • 15
  • 42
  • 3
    The evaluation of arguments to a function is **unsequenced**, not implementation defined. And this is still undefined behavior due to `i` being modified multiple times with no intervening sequence point. – dbush Dec 02 '18 at 15:11
  • Thank you! I have been using GNU GCC Compiler. Which compliers have a different order of evaluation than this? – thegravity Dec 02 '18 at 15:12
  • @dbush https://en.wikipedia.org/wiki/Unspecified_behavior#Implementation-defined_behavior classic example here is relevant to this – Minn Dec 02 '18 at 15:14
  • I have improved my answer, it seems this is actually not implementation defined as I thought it was but rather just unspecified – Minn Dec 02 '18 at 15:19
  • Re “may vary depending on platform or compiler”: This understates the meaning of unsequenced. The behavior may vary upon **any** factor, such as surrounding code, compiler switches, or contents of memory. It can vary even within multiple executions of the same statement within a program. – Eric Postpischil Dec 02 '18 at 15:25
  • Re “code with side-effects should be avoided as much as possible”: That is absurd. The assignment performed by an assignment operator, `=`, is a side effect. You just told people to avoid assigning values to objects. – Eric Postpischil Dec 02 '18 at 15:26
  • Re “This is actually something known as unspecified behavior.” It is undefined behavior. C 2018 6.5 2 says “If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.” – Eric Postpischil Dec 02 '18 at 15:27
  • I said "as much as possible" not "should never be used". – Minn Dec 02 '18 at 15:27
  • @Minn: It is an absurd statement. Modifying a file is also a side effect. These are not things to be avoided, not even avoided “as much as possible.” Yes, programmers need to understand the sequencing rules, and they need to avoid modifying objects in ways unsequenced with other modifications or uses. No, they do not need to avoid side effects “as much as possible.” – Eric Postpischil Dec 02 '18 at 15:29
  • I have removed the parts you criticized, but I do think that its reasonable to avoid side-effects in code as studies have shown that code without side-effects is easier to understand for both mature and beginner programmers. – Minn Dec 02 '18 at 15:33
  • You have not cited any such studies, so I will venture a deduction that they define “side effect” differently from its meaning in C, such as calling functions that change various data in the program in unexpected ways. If not, show us these studies that say we should not write to files. – Eric Postpischil Dec 02 '18 at 15:47
  • This answer still fails to state the behavior of the code in the question is not defined by the C standard. That is the primary conclusion that ought to be drawn from the code, and this answer omits it. (The incidental mention of undefined behavior does not provide the necessary statement.) – Eric Postpischil Dec 02 '18 at 15:49
  • "Its generally best not to have undefined behavior change the outcome of your code." -- Note that C programs with undefined behavior are not valid programs to begin with. Concerning side-effects: functional programmers advocate avoidance of side-effects, but still need them, so strictly control where they happen in code. C is not a functional programming language, so it makes little sense to impose those restrictions here (and would require a _lot_ of extra work in C). Still, there are lessons to be learned from functional programming for C programmers. – ad absurdum Dec 02 '18 at 16:15
  • @DavidBowling: Having behavior not defined by the C standard does not make a program invalid. It makes it not a strictly conforming program, but it may still be a conforming program. The C standard **invites** extensions, which may define behavior that the C standard does not. – Eric Postpischil Dec 02 '18 at 17:23
  • @EricPostpischil -- having _undefined behavior_ makes the program invalid. An implementation may define some behavior for a construct that is otherwise undefined by the Standard, e.g. `fflush(stdin)`. Then the behavior is not _undefined_. Maybe _invalid_ is too strong a word though, since a program may rely on specific implementation details; yet "generally best not to have undefined behavior" seems too ambivalent about UB. – ad absurdum Dec 02 '18 at 17:27
  • @DavidBowling: If you used “undefined behavior” to mean any behavior that is not defined at all, okay. When writing in the context of C, please be aware that “undefined behavior” is a term specifically defined in the C standard. C 2018 3.4.3 defines it to be behavior for which “this document” imposes no requirements. If you use the phrase without qualification, people may think you mean the definition given in the standard. – Eric Postpischil Dec 02 '18 at 17:42
  • @EricPostpischil -- that is a fine distinction, but a fair one; I may have been a bit careless in my wording. – ad absurdum Dec 02 '18 at 17:47