Printf () with no arguments in C compilers is excellent. as?

I tried the following c program, and I expected to get a compile-time error, but why doesn't the compiler give any errors?

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

Why does the output depend on the compiler? Here is the output on different compilers

Exit to Orwell Dev C ++ IDE (uses gcc 4.8.1): 0

Visual C ++ output provided by Visual Studio 2010: 0

CodeBlocks IDE (uses gcc 4.7.1): garbage value

Ideone.com online compiler: the cost of garbage

What's going on here?

+6
source share
10 answers

Your program will compile fine, since printf() is a variational function, and by default the corresponding number of format specifiers are not checked with the argument provided.

At run time, your program exhibits undefined behavior , as there are no arguments that should be printed using the delivery format specifier.

According to chapter 7.19.6.1, c99 standard, (from fprintf() )

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

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

+7
source

Due to the way C variable variables work, the compiler cannot track their proper use. It is still (syntactically) legal to provide fewer or more parameters that a function should perform, although this usually looks like undefined behavior when viewing a standard.

The printf declaration is as follows:

 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 are passed; he can, at best, assume that all the information that he needs has been transferred to him, and nothing more.

Compare this with other languages ​​like C #:

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

Here, the method knows exactly how many additional arguments were passed (execution of arguments.Length ).

In C, function variables and especially printf are a common cause of security vulnerabilities. printf finishes reading raw bytes from the stack, which could leak important information about your application and its security environment.

For this reason, Clang and GCC support a special extension for checking printf formats. If you use the wrong format string, you will receive a warning (not an error).

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

This is just undefined behavior unless you provide enough printf arguments, which means the behavior is unpredictable. From the C99 draft section 7.19.6.1 function fprintf, which also covers printf for this case:

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

Since printf is a variational function , there is no mapping of arguments to a function declaration. Therefore, the compiler must support checking the format string of the support that is being covered - the Wformat flag in gcc :

Check the calls to printf and scanf, etc. to make sure that the arguments provided are of the type matching the specified format string, and that the conversions specified in the format string make sense. This includes standard functions and others defined by format attributes (see Function Attributes), [...]

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

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

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

 printf(const char *,...); 

While making a call

 printf("%d\n"); 

It tries to extract the value from the second argument and, since you did not pass anything, it can receive a certain amount of garbage and print it, so the behavior is undefined here.

+3
source

In general diagnostic messages (you can think of them, for example, compilation errors), undefined behavior (for example, the lack of sufficient arguments to call the printf function as in your case) is not guaranteed, which are not taken into account as a rule of syntax or violation of restrictions.

C11 (N1570) §5.1.1.3 / p1 Diagnostics:

The corresponding implementation must give at least one diagnostic message (defined according to the implementation) if the translation unit for preprocessing or the translation unit violates any syntax rule or restriction , even if the behavior is also explicitly specified as undefined or determined by the implementation. Diagnostic messages should not be made in other circumstances. nine)

In other words, your compiler can freely translate such a unit, but you should never run it or rely on its behavior (since this is de facto unpredictable). In addition, your compiler is allowed not to provide any documentation (that is, the C-standard does not use it for this), as required for implementation-specific or locale-specific behavior.

C11 (N1570) §3.4.3 / p2 undefined behavior:

NOTE. Possible undefined behavior varies from ignoring the situation completely with unpredictable results, behaving during the translation or execution of the program in a documented manner specific to (with or without a diagnostic message), to stop the translation or execution (with the issuing of a diagnostic message).

+2
source

You invoke undefined behavior. That your problem, not the compiler, and basically something is "resolved".

Of course, almost every existing compiler should be able to warn you about this particular state with regard to printf() , you just need to enable it (by turning on and listening to compiler warnings).

+2
source

Using g++ with the -Wall command-line -Wall , you get the following diagnostics:

 g++ -Wall -c -g -MMD -MP -MF "build/Debug/MinGW-Windows/main.od" -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"); ^ 

This is very useful, isn't it?

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

+2
source

According to this documentation, the additional arguments must be no less than the format specifiers in the first argument. This is apparently undefined behavior.

+1
source

what warnings / messages did you use with your compilers? I ran this through gcc (Ubuntu 4.8.2-19ubuntu1) and received a warning

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

and run it also "garbage disposal". here gcc is so smart to parse a format expression and notifies the encoder of the appropriate number of arguments.

what I think: the signature of the printf function is independent of the behavior of the compiled code. at compile time, all compilers must check if at least one argument exists and continues. however, the compiled function will first parse the format expression and, depending on this, read the additional arguments from the function argument stack. in it, it just expects the proper placement of values ​​(int, float, etc.) and uses them. therefore, if you do not specify an argument, the place in the stack of function calls is not reserved, and printf still reads random memory (in this case, in the first place). this also explains the output of the “garbage”, which will be different every 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, what values ​​will be read. "unspecified behavior" is what best describes this effect, sometimes zero, sometimes different.

Hope this clarifies your problem!

+1
source

In the context of printf () and fprintf () according to C standard clause C11 7.21.6.1 "If there are not enough arguments for the format, the behavior is undefined. If the format is exhausted and the arguments remain, the redundant arguments are evaluated (as always), but are ignored otherwise "

-1
source

Source: https://habr.com/ru/post/981672/


All Articles