This question already has answers here:
printf insufficient arguments
(2 answers)
Closed 6 years ago.
Let's say I used printf without passing enough arguments to match the format specifiers:
#include <stdio.h>
int main(void) {
printf("missing argument: %s\n");
}
Are there any guarantees on what the result will be?
On my machine, nothing gets printed at all.
Is this always the case, or is there a potential for it to print the string with an resolved specifier?
for example:
missing argument: %s
or:
missing argument:
The C spec is explicit on this point:
... If there are insufficient arguments for the format, the behavior is undefined. ...
C11dr §7.21.6.1 2
Are there any guarantees on what the result will be? --> No.
(On my machine, nothing gets printed at all.) Is this always the case --> No.
Is there a potential for it to print the string with an resolved specifier? --> Yes. The behavior is undefined. anything may happen.
printf reference states that passing less arguments than specified in the format yields undefined behaviour:
arguments specifying data to print. If any argument is not the type expected by the corresponding conversion specifier, or if there are
fewer arguments than required by format, the behavior is undefined. If
there are more arguments than required by format, the extraneous
arguments are evaluated and ignored
Related
This question already has answers here:
How printf works in case of type mismatch with type specifier?
(3 answers)
Closed 5 years ago.
In an Interview, I was asked the output of the following code snippet:
printf("%d", "computer");
I am a c# developer and earlier I had learned C too, but when this question was asked, I had no clue.
When I run the same question in windows 10 computer (64-bit), it is giving putput as
3571712
Please give reasons why this is happening.
It doesn't "work", what you observe is an outcome of undefined behavior.
Quoting C11, chapter §7.21.6.1/p9
[...] If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
In your case, the conversion specifier is %d which expects an argument of type int but you're supplying a char*, and they are not the compatible type, hence the UB.
well value of "computer" is memory address where that string is stored. It could be value of that address is: 3571712 (But you should not rely on this - see below).
But to print memory address void* you should use %p format specifier. And using incorrect format specifiers is undefined behavior.
In an Interview, I was asked the output of the following code snippet [...]
Your answer could have been:
a. "This is undefined behavior"
b. "A number will most likely be printed, but I cannot tell you which number because I do not know where the string is stored, as the string's address will be attempted to be interpreted as an integer by the printf function".
c. "Which platform? Which compiler?"
It will not work it's giving the garbage value of these variables. And the main reason is that we use "%d" for the output of int not for string.
This simple code is puzzling me - I am deliberately printing out more integers than I passed to printf. I expected an error. I got weird numbers - where are they coming from?
#include <stdio.h>
/* learn arrays */
void main(){
int pout;
pout = 6;
printf("%i %i %i\n%i %i %i\n%i %i %i\n", pout);
}
One example of the output:
6 608728840 0
-885621664 -885543392 608728816
0 0 -889304251
The single digits do not change with repeated runs, but the large integers do.
It's one of printf string format vulnerability. You are trying to call more argument than there actually are, so printf takes whatever he can on the stack.
It was (and still is) very used to exploit programs into exploring stacks to access hidden information or bypass authentication for example.
Viewing the stack
printf ("%08x %08x %08x %08x %08x\n");
This
instructs the printf-function to retrieve five parameters from the
stack and display them as 8-digit padded hexadecimal numbers. So a
possible output may look like:
40012980 080628c4 bffff7a4 00000005 08059c04
See this for a more complete explanation.
Because it's undefined behavior. If the number of specifiers is larger than the number of matching parameters or their types are incompatible, the behavior is undefined.
This qoute is from the c11 standard draft
7.21.6.1 The fprintf function
The fprintf function writes output to the stream pointed to by stream, under control of the string pointed to by format that specifies how subsequent arguments are converted for output. 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. The fprintf function returns when the end of the format string is encountered.
If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
I highlighted the relevant parts making them bold.
The int reserves some RAM but you didn't wrote anything in so it shows you what numbers are random somewhere in your RAM
This question already has an answer here:
Code for printf function in C [duplicate]
(1 answer)
Closed 8 years ago.
What is the exact use of % in scanf and printf? And would scanf and printf work without the % sign? All I could find is that % is the conversion specifier but I want to know how it works actually?
% is simply the symbol used to identify the beginning of a conversion specifier in the format string; why % as opposed to any other symbol is an open question, and probably doesn't have that interesting an answer. The printf and scanf functions search the format string for conversion specifiers to tell them the number and types of additional arguments to expect, and how to format the output (for printf) or interpret the input (for scanf).
To print a literal %, you need to use %%.
printf can work without using a conversion specifier, but you'll be limited to writing literal strings. scanf is pretty useless without it.
The '%' character is used in the format string of the scanf() and print()-like functions from the standard header <stdio.h>, to indicate place holders for variable data of several kinds. For example, the format specifier "%d" is a place holder for a value having type int.
Thus, the variadic function printf() expects additional parameters passed as arguments to the function, the first of them having type int.
The value of this int argument is converted to string, and it will be replace to the place holder "%d".
In the case of scanf(), the situation is similar, but now scanf() is an input function that expects that the user enters in command-line a value fitting on the type indicated by the format specifier. Thus, a format specifier "%d" will expect that the user enters a value of type int.
Since all the arguments in C are passed by value, the input data requires you use the address of the variable, to mimic a by-reference mode of passing arguments.
There are a lot of options and details related to these format specifiers.
Yo need to take a look at the bibliography.
For example, start in Wikipedia:
printf() format string
scanf() format string
The % in a scanf() or printf() is a keyword whose purpose is identify the type of data that will be stored in the named variable. So, in the following example, the compiler would build instructions to accept input data of type integer and store it in the memory location at the address assigned to num1:
int num1;
scanf("%d",&num1);
so as printf() is a function and it returns the number of characters written if successful or negative value if an error occurred, looking at this example, the output as expected is zero.
#include <stdio.h>
int main(void)
{
printf("%d");
return 0;
}
now when I add some more of these %d : http://ideone.com/brw5vG
the output changes to this:
0 134513819 -1216430092 134513808
I am not able to figure out whats up with the random garbage values? There is a negative value here in the output as well, and a negative value justifies an error, so can anyone pinpoint what is the error here exactly?
Please be concise and specific. Thanks.
Because "%d" means an integer is expected. You don't pass any, so you get undefined behaviour.
Note that g++ 4.8.2 gives a useful warning:
warning: format '%d' expects a matching 'int' argument [-Wformat=]
similarly for clang++ 3.4:
warning: more '%' conversions than data arguments [-Wformat]
the output as expected is zero
printf("%d");
You should not expect anything as your program invokes undefined behavior.
(C99, 7.19.6.1p2) "[...] If there are insufficient arguments for the format, the behavior is
undefined.[...]"
You are mis-specifiying the format string to printf this is undefined behavior and you should have no expectations as to the result. By specifying %d you are telling printf to expect an int argument which you have not provided.
If we look at the C99 draft standard section 7.19.6.1 The fprintf function which also covers pritnf with respect to format specifiers says:
[...]If there are insufficient arguments for the format, the behavior is undefined.[...]
The problem is in how you pose the question; you assume it "should be 0." The fact is that this is undefined behavior, and printf will substitute for %d whatever happens to be in the stack.
Your code invokes undefined behavior. Anything could be happen.
The C11 Standard says in section 7.21.6 Formatted input/output functions:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
You are passing no argument for the corresponding %d specifier.
There are 2 issues at hand: First is why doesn't the compiler issue an error about this bad call to printf(), and second is why you get garbage output. I'll answer them one at a time.
printf() is a tricky function. While most functions have a constant amount of arguments passed to them, printf() is different.
For example, if we take this simple function:
int max(int a, int b) {
if (a > b) return a;
else return b;
}
You can see that this function always receives 2 arguments. This is also something that the compiler knows, and enforces when you compile you code. This is why a call such as max(4) won't work. The compiler will see that we are passing max() 1 argument instead of 2 and it will issue an error.
printf() is a function that takes a variable amount of arguments, and this amount is determined by the amount of format specifiers (things that start with %) in the format string. This means that the compiler cannot know at compile time if the amount of arguments that you passed to printf is enough (or maybe too much).
The reason that you get garbage printed is because of how functions read their input arguments. All input arguments for a function reside on the stack. These are pushed into the stack before the function is called and later addressed by the function. In this case, printf() expects to have an extra argument besides the format string (because of the %d), and so it looks in the address where its 2nd argument might have been. Alas, that argument wasn't passed, so it will actually look into a place in the stack that might contain anything else (a return address, a frame pointer, a local variable of an enclosing scope or other).
You can read more about how function calls work here.
This question already has answers here:
Turbo C++: Why does printf print expected values, when no variables are passed to it?
(5 answers)
Closed 9 years ago.
I have just tried to know the output without supplying the variable instead just %d and there is no error in compiling the program but i wonder how the output displayed like below.
#include <stdio.h>
int main()
{
printf("%d");
return 0;
}
The output became 7288368
"why formatting input output requires variable to be supplied?"
Because the implementation of printf demands so. From the manual page of printf:
"Each conversion specification is introduced by the character %, and ends with a conversion specifier... The arguments must correspond properly (after type promotion) with the conversion specifier."
You have used "%d" format string, which expects a integral argument appropriate for decimal conversion, yet you haven't provided any arguments, which resulted in an undefined behavior