7

A question was asked in a multiple choice test: What will be the output of the following program:

#include <stdio.h>

int main(void)
{
    int a = 10, b = 5, c = 2;

    printf("%d %d %d\n");

    return 0;
}

and the choices were various permutations of 10, 5, and 2. For some reason, it works in Turbo C++, which we use in college. However, it doesn't when compiled with gcc (which gives a warning when -Wall is enabled) or clang (which has -Wformat enabled and gives a warning by default) or in Visual C++. The output is, as expected, garbage values. My guess is that it has something to do with the fact that either Turbo C++ is 16-bit, and running on 32-bit Windows XP, or that TCC is terrible when it comes to standards.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
SgrA
  • 289
  • 3
  • 9
  • 9
    Output can be literally anything, since this code results in Undefined Behaviour. – Paul R Aug 22 '13 at 19:28
  • 1
    Yeah the whole compiler thing is a red herring. –  Aug 22 '13 at 19:29
  • In gcc format specifier must need variable name, example printf("%d", x); if not printf will print some value – sujin Aug 22 '13 at 19:29
  • 4
    It would be interesting if OP could let us know if 'undefined behavior' is one of the multiple choice answers. –  Aug 22 '13 at 19:32
  • 7
    I quite don't get why a college would use a discontinued and visibly bad software to teach C or C++, and going as far as asking such nonsensical MCT question, while there are compilers such as GCC and Clang available for free. – SirDarius Aug 22 '13 at 19:36
  • Has tc++ the option of mixed mode listing, where you see always one line of c++ and beyond the generated assembler code? – ott-- Aug 22 '13 at 19:37
  • @sirdarius Like I said, show us the answers before making hasty statements. –  Aug 22 '13 at 19:43
  • @remyabel: No, only permutations of 2, 5 and 10. – SgrA Aug 22 '13 at 19:44
  • In that case, they probably are hinging on the stack order. –  Aug 22 '13 at 19:45
  • @SirDarius Turbo C++ is apparently the standard here, even for teaching C++; I agree it's stupid to teach C with classes under the pretext of C++. – SgrA Aug 22 '13 at 19:47
  • 1
    @remyabel I did not make a hasty statement. The question here demonstrates that turbo c++ does not consider the lack of enough parameters to printf as an error. So "visibly", this is bad. Anyways, the way the question is phrased makes it clear that "undefiend behaviour" is not part of the choices. – SirDarius Aug 22 '13 at 20:11

5 Answers5

20

The code has undefined behaviour.

In Turbo C++, it just so happens that the three variables live at the exact positions on the stack where the missing printf() argument would be. This results in the undefined behaviour manifesting itself by having the "correct" values printed.

However, you can't reasonably rely on this to be the case. Even the slightest change to your build environment (e.g. different compiler options) could break things in an arbitrarily nasty way.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Thanks, this makes sense. I tried the same program (compiled with gcc) several times on Linux, and apparently this coincidence is rather rare. Does the coincidence that they're in the exact stack positions that printf requires them to be have something to do with the way 16-bit programs run on Windows XP? Something like some memory is probably reserved to run specifically that one program? – SgrA Aug 22 '13 at 19:41
  • @SgrA: Quite a few stars have to align for this program to behave in the manner you describe. It would be too simplistic to say that it's because of XP, or because the program is 16-bit. – NPE Aug 22 '13 at 19:45
  • What's intriguing is that it did work as described above every single time in Turbo C++, but never outside of it, which makes me curious. – SgrA Aug 22 '13 at 19:53
  • 3
    @SgrA It's not random, it's a matter of how the compiler lays things out. It's undefined but that doesn't always mean random. It's always going to work **in this situation**. It can easily break from unrelated changes. – Loren Pechtel Aug 22 '13 at 23:49
4

It is an undefined behaviour. So it could be anything.

Try to use

printf("%d %d%d", a,b,c)

Reason:- Local variables are called on the stack and printf in Turbo C++ sees them in the same order in which they were assigned in the stack.

SUGGESTION(From comments):-

Understanding why it behaves in a particular way with a particular compiler can be useful in diagnosing problems, but don't make any other use of the information.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • Yeah, I'm convinced that the output could be anything. I'd like to know why exactly does it work in Turbo C++. – SgrA Aug 22 '13 at 19:31
  • @SgrA:- Updated my answer with the reason although NPE has explained it better!!! :) – Rahul Tripathi Aug 22 '13 at 19:41
  • 1
    @SgrA: Understanding why it behaves in a particular way with a particular compiler can be useful in diagnosing problems, but *don't* make any other use of the information. – Keith Thompson Aug 22 '13 at 19:51
  • @KeithThompson Agreed that I shouldn't be relying on these coincidences, and I'm curious only because I'll be using Turbo C++ for a couple of years in college. – SgrA Aug 22 '13 at 19:55
4

The answer here is that the program could do anything -- this is undefined behavior. According to printf()s documentation (emphasis mine):

By default, the arguments are used in the order given, where each '*' and each conversion specifier asks for the next argument (and it is an error if insufficiently many arguments are given).

If your multiple-choice test does not have a choice for "undefined behavior" then it is a flawed test. Under the influence of undefined behavior, any answer on such a multiple-choice test question is technically correct.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
3

What's actually going on is that arguments are normally passed on the call stack. Local variables are also passed on the call stack, and so printf() sees those values, in whatever order the compiler decided to store them there.

This behavior, as well as many others, are allowed under the umbrella of undefined behavoir

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • You mean "local variables are also placed on the stack" rather than "local variables are also passed on the call stack"... – Floris Dec 09 '13 at 16:16
2

No, it's not related to architecture. It is related to how TurboC++ handles the stack. Variables a, b, and c are locals and as such allocated in the stack. printf also expects the values in the stack. Apparently, TurboC++ does not add anything else to the stack after the locals and printf is able to take them as parameters. Just coincidence.

Mario Rossi
  • 7,651
  • 27
  • 37