不同平台使用不同的行尾符的历史原因

37

为什么DOS/Windows和Mac要使用\r\n和\r作为行尾,而不是\n?这是想与Unix区分开来吗?

现在Mac OS X类似于Unix了,那么苹果是不是会从\r转向\n呢?


3
你想打赌这与线式打印机和/或打字机有关。 - Lawrence Dol
是啊,但他们为什么仍然有不同的行尾呢?这是一个非常烦人的兼容性问题,可以很容易地解决。 - Paul
微软终于修复了记事本的问题...... https://blogs.msdn.microsoft.com/commandline/2018/05/08/extended-eol-in-notepad/ - Reversed Engineer
4个回答

40

DOS继承了CR-LF行结束符(您所说的\r\n,只是将ASCII字符明确表示出来)自CP/M。 CP/M从影响CP/M设计师Gary Kildall的各种DEC操作系统那里继承了它。

使用CR-LF使电传打字机返回打印头到左边缘(CR = carriage return),然后移动到下一行(LF = line feed)。

Unix的开发人员在设备驱动程序中处理这个问题,必要时在向需要它的设备输出时将LF转换为CR-LF。

而如你所猜测的,Mac OS X现在使用LF。


23

回复 @Mark Harrison 的评论...

那些告诉你 Unix 只是“输出程序员指定的文本”,而 DOS 是有问题的人是错的。还有一些声称 DOS 在看到 EOF 字符时标记 EOF 是愚蠢的,这就引出了 EOF 字符的作用是什么的问题。

对于文本文件行尾的约定并没有一个真正的标准 - 只有特定于平台的约定。毕竟,即使 CR-LF、CR 和 LF 也不是曾经使用过的唯一的行尾约定,ASCII 也从未是唯一的字符集。问题在于 C 标准库和运行时,它没有抽象出这个依赖于平台的细节。其他第三代语言(如 Pascal 甚至 Basic)至少在某种程度上解决了这个问题。因此,当为其他平台编写 C 编译器时,需要运行时库的 hack 才能实现与现有源代码和书籍的兼容性。

事实上,Unix 和 Multics 最初需要对控制台 I/O 进行字符串转换,因为用户通常坐在需要 CR LF 行尾的 ASCII 终端上。虽然这个转换是在设备驱动程序中完成的,但目标是抽象出设备的具体细节,假设采用一种约定并坚持将其用于存储的文本文件中是更好的。

C文本I/O hack的原理类似于CygWin现在所做的,即通过修改Linux运行时使其在Windows上能够正常工作。有一个真实的黑客历史,将一些东西黑进去,使它们变成类Unix系统 - 但是也有Wine,将Linux变成Windows。奇怪的是,在CygWin FAQ(2013年添加的Internet Archive链接 - 该页面已不存在)中可以读到一些关于Windows换行符的批评。也许这只是他们的幽默感,因为他们基本上正在批评自己所做的事情,但规模更大而已;-)

C++标准库(无论在哪个平台上实现)都使用iostreams来避免这个问题,这样就可以抽象掉行尾。对于输出,这对我来说很好。对于输入,我需要更多的控制,所以我要么逐个字符解释,要么使用扫描器生成器。

[编辑:结果证明上面划掉的说法是错误的,也从未正确。 std::endl 直译为一次 \n 和一次强制冲洗缓存。 该 \n 正好是 C 中所使用的 \n——虽然人们倾向于称其为“换行符”,但实际上它是一个 ASCII 换行字符,如果需要,则由运行时转换。 非常有趣的是,错误的假设可以如此根深蒂固,以至于您从未质疑过它——基本上,C++ 在兼容性方面除了在顶部添加更多层之外,别无选择比仿效 C,这一点应该一直很明显。

从我的角度来看,最大的责任在于 C,但 C 并不是唯一一个没有预料到移植到其他平台的项目。指责比尔·盖茨只是疯狂的行为——他所做的只是购买和改良当时流行的 CP/M 的变种。实际上,这只是历史原因——这就是为什么我们不知道大多数文本文件中的字符代码 128 到 255 参考什么。鉴于处理所有三种行末约定的便捷性,仍然奇怪为什么有些开发人员仍然坚持那种“我平台的约定是唯一正确的方式,不管你喜欢还是不喜欢,我都会强制施加它”的态度。

还有,Unicode行分隔符代码点U+2028是否会在未来的文本文件中替换所有这些约定呢?;-)


9

有趣的是,CRLF几乎成为了互联网标准。也就是说,几乎所有基于行的标准互联网协议都使用CRLF,如SMTP、POP、IMAP、NNTP等。电子邮件正文由以CRLF结尾的行组成。


1
我很好奇,有没有可能以某种方式支持这个主张?在我看来,这会让它更加可信。 - Fred
4
@Fred:只需要查看定义协议的RFC文档。例如,定义HTTP 1.1的RFC2616规定,报头的行分隔符为CR+LF。(对于某些内容类型的有效载荷行分隔符可能被解释得更加宽松,但其中许多也是正式的CR+LF。)https://tools.ietf.org/html/rfc2616#section-2.2 - Adrian McCarthy
1
很多关于“互联网”的原始工作都是在DEC计算机上完成的,我知道。但是我对这个小事实感到惊讶,因为似乎大多数计算机都在运行UNIX系统。 - bobwki

0
根据维基百科:起初,程序必须在LF之前插入额外的CR字符以减慢程序速度,以便打印机有时间跟上 - CP/M和后来的Windows使用了这种方法。但Multics的打印机驱动程序会自动插入额外的字符,因此程序不必这样做 - Unix开发人员从中受益。但是,这并不能解释为什么早期的Mac没有这样做(现在它们基于Unix)。

https://en.wikipedia.org/wiki/Newline#History:

序列CR + LF通常用于许多早期计算机系统,这些系统采用了Teletype机器(通常是Teletype Model 33 ASR)作为控制台设备,因为此序列需要将打印机定位到新行的开头。将换行符分成两个功能隐藏了一个事实,即打印头无法及时从最右边返回到下一行的开头位置以打印下一个字符。在CR之后打印的任何字符通常会在页面中间打印出污点,而打印头仍在将载体移回第一个位置。 “解决方案是使换行符成为两个字符:CR将车移动到第一列,LF将纸向上移动。”[1] 实际上,通常需要发送额外的字符 - 多余的CR或NUL,这些字符被忽略但给打印头时间向左边距移动。许多早期视频显示器也需要多个字符时间来滚动显示。

在这样的系统上,应用程序必须直接与Teletype机器交互并遵循其惯例,因为设备驱动程序隐藏这些硬件细节的概念尚未得到良好发展。因此,文本通常是为了满足Teletype机器的需求而组成的。 DEC的大多数小型计算机系统都使用了这种约定。 CP / M也使用它以便在与小型计算机使用的相同终端上打印。从那里,MS-DOS(1981年)采用了CP / M的CR + LF以实现兼容性,并且这种约定被Microsoft的后来的Windows操作系统所继承。

Multics操作系统始于1964年,仅使用LF作为换行符。 Multics使用设备驱动程序将此字符转换为打印机需要的任何序列(包括额外的填充字符),而单个字节对于编程更方便。似乎更明显的选择 - CR - 没有使用,因为CR提供了一个有用的功能,即通过另一行覆盖一行以创建粗体和删除线效果。也许更重要的是,仅使用LF作为行终止符已经并入了最终ISO / IEC 646标准的草案中。 Unix遵循Multics的做法,后来的类Unix系统也遵循Unix。这在Windows和类Unix操作系统之间创建了冲突,因此在一个操作系统上组成的文件可能无法被另一个操作系统正确格式化或解释(例如,在Windows文本编辑器(如记事本)中编写的UNIX shell脚本)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接