Reputation: 14438
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
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
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
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
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
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
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
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
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
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
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