Destructor
Destructor

Reputation: 14438

printf() with no arguments in C compiles fine. how?

I tried the below c program & I expected to get compile time error, but why compiler isn't giving any error?

#include <stdio.h>
int main(void)
{
    printf("%d\n");
    return 0;
}

Why output is compiler dependent? Here is the output on various compilers

Output on Orwell Dev C++ IDE (uses gcc 4.8.1) : 0

Output on Visual C++ provided by Visual Studio 2010 : 0

CodeBlocks IDE (uses gcc 4.7.1) : garbage value

Online compiler ideone.com : garbage value

What is going wrong here ?

Upvotes: 9

Views: 3541

Answers (10)

Karthik Sagar
Karthik Sagar

Reputation: 444

In the context of printf() and fprintf(), as per C standard C11 clause 7.21.6.1, "If there are insufficient arguments for the format, the behavior is undefined. If the format is exhausted while arguments remain, the excess arguments are evaluated (as always) but are otherwise ignored."

Upvotes: -1

Axel Kemper
Axel Kemper

Reputation: 11322

Using g++ with commandline parameter -Wall produces the following diagnostics:

g++ -Wall   -c -g -MMD -MP -MF "build/Debug/MinGW-Windows/main.o.d" -o build/Debug/MinGW-Windows/main.o main.cpp
main.cpp: In function 'int main(void)':
main.cpp:17:16: warning: format '%d' expects a matching 'int' argument [-Wformat=]
     printf("%d");
                ^

That's pretty useful, isn't it?

gcc/g++ also check if the format specifiers actually match the parameter types. This is really cool for debugging.

Upvotes: 2

Grzegorz Szpetkowski
Grzegorz Szpetkowski

Reputation: 37934

In general diagnostic messages (you may think of them like compilation errors) are not guaranteed for undefined behaviors (like lack of sufficient arguments for printf function call as in your case), that are not counted as syntax rule or constraint violations.

C11 (N1570) §5.1.1.3/p1 Diagnostics:

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances.9)

In other words your compiler is free to translate such unit, but you should never run it or rely on its behaviour (as it's de facto unpredictable). Moreover your compiler is allowed not to provide any documentation (that is C Standard does not enforce it to do so), like it's required for implementation-defined or locale-specific behaviours.

C11 (N1570) §3.4.3/p2 undefined behavior:

NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

Upvotes: 2

daniel.wirtz
daniel.wirtz

Reputation: 1030

what warnings/messages did you get using your compilers? i ran this through gcc (Ubuntu 4.8.2-19ubuntu1) and got a warning

warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
     printf("%d\n");
     ^

and running it also "garbage output". here, the gcc is so clever to parse the format expression and notifies the coder to provide a matching number of arguments.

what i think happens: the function signature of printf is independent from the behaviour of the compiled code. at compile time, all the compiler cares is to check if at least one argument is there and continues. however, the compiled function will first parse the format expression and, dependent on that, read further arguments from the functions' arguments stack. therein it simply expects appropriately put values (int, float etc) and uses them. so if you dont specify the argument, no place on the function call stack is reserved and printf still reads random memory (in this case at the first location). this also explains the "garbage" output, which will differ each time you call the binary. you can even extend the code to

#include <stdio.h>
int main(void)
{
    printf("%d\n%d\n");
    return 0;
}

and get two different garbage numbers :)

then again it will depend on the environment/process/compiler which values will be read. "unspecified behaviour" is what describes this effect best, sometimes zero, sometimes other.

i hope this clarifies your issue!

Upvotes: 1

Gopi
Gopi

Reputation: 19864

This compiles well. Because it matches the printf() prototype which is

printf(const char *,...);

During run-time the call

printf("%d\n");

Tries to fetch the value from second argument and since you have not passed anything it might get some garbage value and print it out so the behavior is undefined here.

Upvotes: 3

Shafik Yaghmour
Shafik Yaghmour

Reputation: 158489

This is simply undefined behavior if you do not provide the sufficient arguments to printf, which mean the behavior is unpredictable. From the draft C99 standard section 7.19.6.1 The fprintf function which also covers printf for this case:

If there are insufficient arguments for the format, the behavior is undefined.

Since printf is a variadic function there is no matching of arguments to the function declaration. So the compiler needs to support support format string checking which is covered by -Wformat flag in gcc:

Check calls to printf and scanf, etc., to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense. This includes standard functions, and others specified by format attributes (see Function Attributes), [...]

Enabling sufficient compiler warnings is important, for this code gcc using the -Wall flag tells us (see it live):

 warning: format '%d' expects a matching 'int' argument [-Wformat=]
 printf("%d\n");
 ^

Upvotes: 4

zneak
zneak

Reputation: 138061

Because of how C variadic arguments work, the compiler cannot track their correct usage. It is still (syntactically) legal to provide less, or more, parameters that the function needs to work, although this generally ends up as undefined behavior when looking at the standard.

The declaration of printf looks like this:

int printf(const char*, ...);

The compiler only sees ..., and knows that there may be zero or more additional arguments that the function may or may not use. The called function does not know how many arguments it is passed; it can, at best, assume that it was passed all the information it needs and nothing more.

Contrast this with other languages, like C#:

void WriteLine(string format, params object[] arguments);

Here, the method knows exactly how many additional arguments is was passed (doing arguments.Length).

In C, variadic functions and especially printf are a frequent cause of security vulnerabilities. Printf ends up reading raw bytes from the stack, which may leak important details about your application and its security environment.

For this reason, Clang and GCC support a special extension to validate printf formats. If you use an invalid format string, you'll get a warning (not an error).

code.c:4:11: warning: more '%' conversions than data arguments [-Wformat]
    printf("%d\n");
           ~~^

Upvotes: 7

Sourav Ghosh
Sourav Ghosh

Reputation: 134336

Your program will compile fine, as printf() is a variadic function and the matching check of the number of format specifiers with supplied argument is not performed by default.

At runtime, your program exhibits undefined behaviour, as there in no argument supplied which has to be printed using the supplied format specifier.

As per chapter 7.19.6.1, c99 standard, (from fprintf())

If there are insufficient arguments for the format, the behavior is undefined.

If you compile using -Wformat flag in gcc, your compiler will produce the warning for the mismatch.

Upvotes: 11

DevSolar
DevSolar

Reputation: 70283

You are invoking undefined behaviour. That's your problem, not the compiler's, and basically anything is "allowed" to happen.

Of course, virtually every existing compiler should be able to warn you about this particular condition regarding printf(), you just have to allow him to (by enabling, and heeding, compiler warnings).

Upvotes: 2

Codor
Codor

Reputation: 17605

According to this documentation, the additional arguments must be at least as many as the format specifiers in the first argument. This seems to be undefined behaviour.

Upvotes: 1

Related Questions