为什么printf
在使用ASCII表中的NULL字符时打印空格而不是停止?这就是我的意思:
printf("Hello%c, world", 0); //Hello , world
printf("Hello%c, world", '\0'); //Hello , world
只有当我将转义字符放在字符串本身printf
时才会停止字符串:
printf("Hello\0, world"); //Hello
我在Windows 8,Windows 10(使用cygwin,MinGW,Netbeans,Code :: Blocks),XUbuntu上试过这个,它都是一样的。
问题出在哪里?我问过我的一个朋友,但他说他没有这样的问题,所有三个例子都以同样的方式执行。
答案 0 :(得分:22)
printf("Hello\0, world");
将其参数用作 C-string ,因此它会对其进行解码,直到找到NUL字符,因此它会在\0
之后停止,忽略后面的内容。< / p>
printf("Hello%c, world", 0);
解码其参数(直到它在其中找到一个NUL字符 - 即在d
之后),同时它找到一个%c
,所以它用给定的字符替换它作为参数(其ASCII码为NUL),然后向终端发送NUL字符,然后继续。
Printf手册说:
这些函数在格式字符串的控制下写入输出 指定后续参数[...]的转换方式 输出
答案 1 :(得分:6)
您依赖于printf()实现细节。低级终端输出函数需要字符串的长度作为参数。 printf()有两种方法可以做到这一点。
有点明显的方法是首先格式化字符串,然后使用strlen()。这就是你所希望的那个。
但这样做效率很低,因为它需要在字符串缓冲区中进行双重传递并附加0.另一种方法是在替换字段时跟踪格式化的字符串长度,只需为每个附加字符递增它。由于它会继续超过%c,因此您现在可以获得更大的长度,包括过去%c的所有内容。终端函数对嵌入式0的作用也是一个实现细节,因为它不是可打印的字符。看到它被空格取代并不罕见。
这样做的方法是不依赖于实施细节。
答案 2 :(得分:1)
printf("Hello%c, world", 0); //Hello , world
printf("Hello%c, world", '\0'); //Hello , world
在这两种情况下,您都试图打印出与字符代码0
对应的字符值,该字符代码不是可打印字符。我没有找到关于它的章节和经文,但我怀疑尝试打印一个空字符值的行为是未指定的,甚至可能是未定义的。无论哪种方式,我都不希望在这种情况下将其视为字符串终止符。
printf("Hello\0, world"); //Hello
在这种情况下,nul字符是字符串常量的一部分,并由编译器解释为字符串终止符。
答案 3 :(得分:0)
简而言之:
%c
表示打印字符,因此printf
打印值为0的NUL
字符。NUL
是非打印字符。所以我们只能看到那里的空间。
“Hello \ 0,world”是一个字符串文字,strlen("Hello\0, world")
的结果是5.所以printf
将打印结果“Hello”。
您可以在网站cppreference上看到更多信息:string literal
字符串文字是用双引号括起来的零个或多个多字节字符的序列,如“xyz”中所示。空字符('\ 0')始终附加到字符串文字,因此,字符串文字“Hello”是一个const char [6],其中包含字符'H','e','l','l' ,'0'和'\ 0'。如果字符串文字嵌入了空字符,则表示包含多个字符串的数组。