Is it undefined behavior to print null pointers with the %p
conversion specifier?
#include <stdio.h> int main(void) { void *p = NULL; printf("%p", p); return 0; }
The question applies to the C standard, and not to C implementations.
char* p = NULL; printf("%s", p); What should be the output of the above program? The print expects a '\0' terminated array of characters (or string literal) whereas it receives a null pointer. Passing NULL to printf is undefined behavior.
Yes. Printing null pointers with the %p conversion specifier has undefined behavior.
Null dereferencingBecause a null pointer does not point to a meaningful object, an attempt to dereference (i.e., access the data stored at that memory location) a null pointer usually (but not always) causes a run-time error or immediate program crash. In C, dereferencing a null pointer is undefined behavior.
The null character is only used to signify the end of a string, and should not be printed. More than one call to printf() can contribute to the same 'formatted line'.
This is one of those weird corner cases where we're subject to the limitations of the English language and inconsistent structure in the standard. So at best, I can make a compelling counter-argument, as it's impossible to prove it :)1
The code in the question exhibits well-defined behaviour.
As [7.1.4] is the basis of the question, let's start there:
Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, [... other examples ...]) [...] the behavior is undefined. [... other statements ...]
This is clumsy language. One interpretation is that the items in the list are UB for all library functions, unless overridden by the individual descriptions. But the list starts with "such as", indicating that it's illustrative, not exhaustive. For example, it does not mention correct null-termination of strings (critical for the behaviour of e.g. strcpy
).
Thus it's clear the intent/scope of 7.1.4 is simply that an "invalid value" leads to UB (unless stated otherwise). We have to look to each function's description to determine what counts as an "invalid value".
strcpy
[7.21.2.3] says only this:
The
strcpy
function copies the string pointed to bys2
(including the terminating null character) into the array pointed to bys1
. If copying takes place between objects that overlap, the behavior is undefined.
It makes no explicit mention of null pointers, yet it makes no mention of null terminators either. Instead, one infers from "string pointed to by s2
" that the only valid values are strings (i.e. pointers to null-terminated character arrays).
Indeed, this pattern can be seen throughout the individual descriptions. Some other examples:
[7.6.4.1 (fenv)] store the current floating-point environment in the object pointed to by
envp
[7.12.6.4 (frexp)] store the integer in the int object pointed to by
exp
[7.19.5.1 (fclose)] the stream pointed to by
stream
printf
[7.19.6.1] says this about %p
:
p
- The argument shall be a pointer tovoid
. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
Null is a valid pointer value, and this section makes no explicit mention that null is a special case, nor that the pointer has to point at an object. Thus it is defined behaviour.
1. Unless a standards author comes forward, or unless we can find something similar to a rationale document that clarifies things.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With