18

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 上试过这个,都是一样的。

问题出在哪里?我问了我的一位朋友,但他说他没有这样的问题,所有三个示例都以相同的方式执行。

4

4 回答 4

22

printf("Hello\0, world");将其参数用作C 字符串,因此它对其进行解码,直到找到 NUL 字符,因此它在 之后停止\0,忽略后面的内容。

printf("Hello%c, world", 0);解码它的参数(直到它在其中找到一个 NUL 字符 - 即 after d),同时它找到 a %c,所以它用作为参数给出的字符(其 ASCII 码是 NUL)替换它,然后向终端发送一个 NUL 字符,然后继续。

Printf 手册说:

这些函数在格式字符串的控制下写入输出,该格式字符串指定后续参数 [...] 如何转换为输出。

于 2015-10-22T10:47:16.230 回答
6

您正在依赖 printf() 实现细节。低级终端输出函数需要字符串的长度作为参数。printf() 有两种方法可以做到这一点。

比较明显的方法是格式化字符串,然后使用 strlen()。那是你所希望的。

但这是低效的,因为它需要在字符串缓冲区中进行两次传递并附加 0。另一种方法是在替换字段时跟踪格式化的字符串长度,只需为每个附加的字符递增它。由于它继续超过 %c,您现在将获得更大的长度,包括超过 %c 的所有内容。终端函数对嵌入的 0 所做的也是一个实现细节,因为它不是可打印的字符。用空格代替它并不少见。

解决这个问题的明智方法是不依赖于实现细节。

于 2015-10-22T11:15:11.300 回答
1
printf("Hello%c, world", 0); //Hello , world
printf("Hello%c, world", '\0'); //Hello , world

在这两种情况下,您都试图打印出与字符 code 对应的字符值0,这不是可打印的字符。我还没有找到关于它的章节,但我怀疑尝试打印 nul 字符值的行为是未指定的,甚至可能是未定义的。无论哪种方式,我都不希望它在这种情况下被视为字符串终止符。

printf("Hello\0, world"); //Hello

在这种情况下,nul 字符是字符串常量的一部分,并被编译器解释为字符串终止符。

于 2015-10-22T13:03:29.377 回答
0

简而言之: %c就是打印一个字符,所以printf打印NUL值为0NUL的字符。是非打印字符。所以我们只能在那里看到一个空间。

"Hello\0, world" 是一个字符串文字,结果strlen("Hello\0, world")是 5。所以printf会打印结果 "Hello"。

您可以在网站 cppreference 上查看更多信息:字符串文字

字符串文字是用双引号括起来的零个或多个多字节字符序列,如“xyz”。空字符 ('\0') 总是附加到字符串文字后,因此,字符串文字 "Hello" 是一个 const char[6] 包含字符 'H'、'e'、'l'、'l' 、'0' 和 '\0'。如果字符串文字嵌入了空字符,则它表示包含多个字符串的数组。

于 2015-10-22T17:54:21.183 回答