为什么当我们在文件中写\ n时它会转换为\ r \ n组合?

我从书中读到这个概念,当我们尝试使用fputs()将文件写入文件时,fputs()将\ n转换为\ r \ n组合,然后如果我们使用fgets()读回同一行,则反向转换发生意味着\ r \ n回转换为\ n。 我不知道这背后的目的是什么?

这是因为Windows(和MS-DOS)文本文件应该以\ r \ n结尾的行,并且可移植C程序应该只使用\ n,因为C最初是在Unix上定义的。

并且不仅仅是fputs和fgets这样做 – 文本文件上的任何I / O函数,甚至是getc和fread,都将进行相同的转换。

简而言之,DOS就是这个原因。

不同的系统对行结尾有不同的约定。 Unix估计一个字符, '\n'足以标记一行的结尾。 DOS决定它需要两个字符, '\r''\n' ,尽管其他系统也使用该约定。 Mac OS 1-9的版本(在Mac OS X之前)仅使用'\r' 。 其他系统可以使用计数和行数据而不是行结束,或者可以模拟具有最大固定长度(72或80)的空白的穿孔卡。 Unix也不区分二进制文件和文本文件; DOS确实如此。 (DOS也使用Control-Z在文本文件中标记EOF。Unix没有EOF标记;它确切知道文件的大小,并使用该长度来确定何时达到EOF。)

C源于Unix,但为了便于在系统之间迁移代码,标准I / O包定义了当它处理文本文件时,输入端会将本机行结尾转换为单个'\n'字符对于统一输入,输出端将'\n'转换为本机行结尾。

但是,提及文本文件也意味着需要二进制文件,这些映射不会发生。

您可能会注意到,大多数互联网协议(例如,HTTP)都要求行标记的CRLF(回车符,换行符或'\r''\n' )。

(实际上,指责DOS,就像在MS-DOS或PC-DOS中一样,有点不公平。在DOS存在之前,还有其他系统使用CRLF线路终端约定,它们可能在互联网上更有影响力。但是,几乎所有这些祖先系统都基本上不存在了,而Windows是你最近会遇到的环境,二元文本和文本文件之间的区别很重要,而且你会遇到CRLF行结束的地方。)

请注意,C标准对文本文件有这样的说法:

ISO / IEC 9899:2011§7.21.2文件

¶2文本流是由行组成的有序字符序列,每行由零个或多个字符加上一个终止的换行符组成。 最后一行是否需要终止换行符是实现定义的。 可能必须在输入和输出上添加,更改或删除字符,以符合在主机环境中表示文本的不同约定。 因此,流中的字符与外部表示中的字符之间不需要一一对应。 从文本流读入的数据必须与之前写入该流的数据相等,只有在以下情况下:数据仅包含打印字符,控制字符包含水平制表符和新行; 空格字符前面不会有任何换行符; 最后一个字符是换行符。 在读入时是否出现在换行符之前立即写出的空格字符是实现定义的。

这可能会或可能不会发生很多事情。 请特别注意,根据标准,写入文件的尾随空白可能会或可能不会出现在输入中。 这允许支持穿孔卡图像或固定长度记录的系统符合标准。

请注意(正如Giacomo Degli Eposti所指出的),这一切都意味着如果你打开一个最初写成文本文件的二进制模式的文件,你很可能从我那里得到一个明显不同的字节列表/ O系统。 你会看到每个换行符有两个字符; 您可能会看到一个Control-Z后跟其他字符(可能是空字节),直到’block’边界,可能是256字节的倍数,等等。