Reputation: 50667
I know that, to use printf()
correctly, we need to further pass in same number of values according to what are defined in the const char* format
, i.e. %s/%f/%d...
.
int printf( const char* format, ... );
I just noticed that, although not recommended, it will run without any run-time errors if we don't pass in any values, like the following (of course, we will get un-expected results):
printf("%a"); // ok
printf("%c"); // ok
printf("%d"); // ok
printf("%e"); // ok
printf("%f"); // ok
printf("%g"); // ok
printf("%i"); // ok
printf("%o"); // ok
printf("%p"); // ok
printf("%u"); // ok
printf("%x"); // ok
If this will holds for all formats, I will feel no surprised by thinking that printf()
doesn't do any run-time checking. Weird thing is that, it will give run-time error for %s
(also seems the only one).
printf("%s"); // run-time error: Access violation reading location
Even more interesting thing is that, it seems that it only run-time checks for the first or consecutive of %s
. Check out the following examples:
printf("%s%s", "xxx"); // run-time error: Access violation reading location
printf("%s%d%s", "xxx"); // ok
So, my question is that:
printf()
run-time check differently for %s
compared with other formats? And why?printf()
only run-time check for the first or consecutive of %s
?ps: I tested it under VS2010, OS: Win7x64.
Upvotes: 2
Views: 1226
Reputation: 101484
[ED: Note this question was originally tagged C++, and this answer assumes OP is compiling as C++]
although not recommended, it will run without any run-time errors if we don't pass in any values,
No, this yields Undefined Behavior. Anything can happen, including what you expect. Doesn't mean it's OK.
printf
does no runtime checking of whatever junk you send it, if you send it anything at all. The onus is upon you to ensure you write correct code.
By the way ion your later case where you were getting "unhandled exception" errors -- this was not the result of sprintf
doing runtime checking. This was another manifestation of Undefined Behavior.
All of this odd and dangerous behavior is a result of the fact that sprintf is a type-unsafe, dangerous function. It is very easy to write code that the compiler will happily accept, and will seem to run fine in testing or even in production for a while, but exhibits Undefined Behavior in some subtle way. This usually bites you on Fridays an hour before you're going out for the weekend.
The life lesson here is: don't use sprintf in C++. Use something modern and type-safe instead, like streams.
Upvotes: 2
Reputation: 7970
There are no runtime checks, techically hard to do those. But there are compilation checks available.
With GCC it's -Wall
.
With Visual Studio you need to run it's static analysis tool (available on the more expensive versions).
Upvotes: 1
Reputation: 158559
In this case the C++ standard fall back on the C99 draft standard which says this is undefined behavior in section 7.19.6.1
The fprintf function which covers printf
with respect format specifiers, says:
[...]If there are insufficient arguments for the format, the behavior is undefined.
So as the standard says in the definition for undefined behavior:
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).
anything can happen.
Since printf
is a variadic function it has to rely on the caller to correctly represent the data passed in. So run time checking is not possible. Although several compilers do provide compile time checking, for example gcc
even provides this checking as an attribute format (archetype, string-index, first-to-check) which can be used with your own functions.
Upvotes: 6
Reputation: 30136
printf("%d")
: An attempt to read 4 bytes from a possibly-illegal memory address.
printf("%s")
: An attempt to read an unknown number of bytes from a possibly-illegal memory address, until a byte with value 0 is encountered.
In both cases, it's a "matter of luck" whether or not a memory access violation will take place.
But as you can understand, these chances are much higher in the case of "%s"
.
Upvotes: 0
Reputation: 21003
It is undefined behaviour, so anything may happen. In practice the difference you see may be due to the fact that all other specifiers you used refer to values directly on the stack, so garbage is displayed, but it does not crash. With %s it is different - the random value is treated as pointer, and your program accesses the random area of memory, so most likely it crashes. Having said that, it is still undefined and should not be used.
Upvotes: 0
Reputation: 272667
There are no runtime checks. printf
will just blindly read whatever gibberish is on the stack (or whatever var-arg mechanism is being used). In the case of %s
, it interprets the gibberish as a pointer, and then attempts to read stuff from that address, typically leading to an access violation.*
In essence, what you're seeing is undefined behaviour.
* Ok, I guess this is a sort-of runtime check, at the OS/HW level.
Upvotes: 2