'\0' 是否自然出现在文本文件中?

Does '\0' appear naturally in text files?

我今天遇到了一个有点烦人的错误,字符串(存储为 char[])最后会打印出垃圾。假设要打印的字符串(使用 arduino print/write 函数)是正确的(它正确地包含 \r 和 \n)。但是,最后会打印出垃圾。

然后我分配了一个额外的元素来存储 '\0' 在 '\r' 和 '\n' 之后(这是要打印的字符串中的最后 2 个字符)。然后,print() 正确地打印了字符串。似乎 '\0' 用于向 print() 函数指示字符串已终止(我记得在 Kernighan 的 C 中读过这个)。

这个错误出现在我从文本文件读取的代码中。我突然想到,我在设计代码时根本没有遇到'\0'。这使我相信 '\0' 在文本编辑器中没有实际用途,仅供打印功能使用。这是正确的吗?

This leads me to believe that '[=13=]' has no practical use in text editors and are merely used by print functions. Is this correct?

这是错误的。在 C 中,字符串的结尾由 [=10=] 字符指定。这通常称为 空终止符 。在 <string.h> 下的 C 库中声明的几乎所有字符串函数都使用此条件来检查或查找字符串的结尾。

另一方面,文本文件通常不会包含任何 [=10=] 个字符。因此,当从文件中读取文本时,您必须先 null-terminate 字符缓冲区,然后再打印它。

[=10=] 是空字符(ASCII 代码 0)的 C 转义序列,广泛用于表示内存中字符串的结尾 。该字符通常不会显式出现在文本文件中,但是,按照惯例,大多数 C 字符串末尾都包含一个空终止符。将字符串读入内存的函数通常会附加一个 [=10=] 来表示字符串的结尾,而从内存输出字符串的函数同样会期望一个 [=10=].

请注意,还有其他方法可以在内存中表示字符串,例如 (length, content) 对(Pascal 特别使用这种表示法),因为字符串的长度已知,所以不需要空终止符提前。

普通文本文件

空字符'[=10=]',即使很少见,也可以出现在文本文件中。代码应准备好处理读取 '[=10=]'.

这还包括典型 ASCII 范围之外的其他 char,可能为负数 signed char.

UTF-16

一些“文本”文件使用 UTF-16 编码和遇到这种情况的代码,但预计典型的“文本”文件会遇到许多空字符。

行长

行可以太长,也可以太短(仅 "\n")。或者可能存在其他“文本”问题。


健壮的代码不信任 use/file 输入,直到它合格并满足预期。它不假定 空字符 不存在。

C 字符串由 NUL 字节 ('[=10=]') 终止 - 这隐式附加到双引号中的任何字符串文字,并用作所有对字符串进行操作的标准库函数的终止符。由此可见,C 字符串不能在其他字符之间包含 '[=10=]' 终止符,因为无法判断它是否是字符串的实际结尾。

(当然你可以用 C 语言处理字符串而不是 C 字符串 - 例如,简单地添加一个整数来记录字符串的长度将使终止符变得不必要,但这样的字符串不能与需要 C 字符串的函数。)

A​​ "text file" 通常不受 C 标准的约束,并且 C 程序的用户可以想象将包含 NUL 字节的文件作为 C 程序的输入(这将无法处理它 "correctly" 由于上述原因,如果它将文件读入 C 字符串)。但是,NUL 字节没有存在于纯文本文件中的正当理由,并且它至少可以被认为是文本文件的事实标准,它们不包含 NUL 字节(或某些其他控制字符,这可能会中断传输该文本通过一些终端或串行协议)。

我认为对于处理纯文本输入的程序来说,如果输入中有 NUL 字节则不能保证正确的输出,这是可以接受的(虽然不是必需的!)限制。然而,程序员应该意识到这种可能性,无论它是否会被正确对待,并且不允许它在他们的程序中导致未定义的行为。与所有用户输入一样,它应该被视为 "unsafe",因为它可以包含任何内容(例如,它可能是故意恶意形成的)。