printf("... %c ...",'\0') and family - what will happen?
How will various functi开发者_如何学运维ons that take printf format string behave upon encountering the %c
format given value of \0
/NULL
?
How should they behave? Is it safe? Is it defined? Is it compiler-specific?
e.g. sprintf()
- will it crop the result string at the NULL? What length will it return?
Will printf()
output the whole format string or just up to the new NULL?
Will va_args
+ vsprintf
/vprintf
be affected somehow? If so, how?
Do I risk memory leaks or other problems if I e.g. shoot this NULL at a point in std::string.c_str()?
What are the best ways to avoid this caveat (sanitize input?)
Any function that takes a standard C string will stop at the first null, no matter how it got there.
When you use the %c in a format and use 0 for the character value, it will insert a null into the output. printf
will output the null as part of the output. sprintf
will also insert the null into the result string, but the string will appear to end at that point when you pass the output to another function.
A std::string will happily contain a null anywhere within its contents, but when you take the c_str method to pass it to a function see the above answer.
What happens when you output a NUL depends on the output device.
It is a non printing character, i.e. isprint('\0') == 0
; so when output to a display device, it has no visible affect. If redirected to a file however (or if calling fprintf()
), it will insert a NUL (zero byte) into the file; the meaning of that will depend on how the file is used.
When output to a C string, it will be interpreted as a string terminator by standard string handling functions, although any other subsequent format specifiers will still result in data being placed in the buffer after the NUL, which will be invisible to standard string handling functions. This may still be useful if ultimately the array is not to be interpreted as a C string.
Do I risk memory leaks or other problems if I e.g. shoot this NULL at a point in std::string.c_str()?
It is entirely unclear what you mean by that, but if you are suggesting using the pointer returned by std::string.c_str()
as the buffer for sprintf()
; don't! c_str()
returns a const char*
, modifying the string through such a pointer is undefined. That however is a different problem, and not at all related to inserting a NUL into a string.
What are the best ways to avoid this caveat (sanitize input?)
I am struggling to think of a circumstance where you could "accidentally" write such code, so why would you need to guard against it!? Do you have a particular circumstance in mind? Even though I find it implausible, and probably unnecessary, what is so hard about:
if( c != 0 )
{
printf( "%c", c ) ;
}
or perhaps more usefully (since there are other characters you might want to avoid in the output)
if( isgraph(c) || isspace(c) )
{
printf( "%c", c ) ;
}
which will output only visible characters and whitespace (space, '\t'
,'\f'
,'\v'
,'\n'
,'\r'
).
Note that you might also consider isprint()
rather than isgraph(c) || isspace(c)
, but that excludes '\t'
,'\f'
,'\v'
,'\n'
and '\r'
printf()
and sprintf()
will continue past a '\0'
character inserted with %c
, because their output is defined in terms of the content of the format string, and %c
does not denote the end of the format string.
This includes their count; thus:
sprintf(x, "A%cB", '\0')
must always return 3 (although strlen(x)
afterwards would return 1).
精彩评论