\r,\n,\r\n那些事

1

用电脑的都知道enter键是回车键,实际上应该叫回车换行键才准确,因为作用不仅仅是回车,还有换行的作用。今天说一说回车、换行的那些事。

这一切要从古早的电传打字机说起。当我们在电传打字机上打完一行字时,那么就要进行两个操作,回车和换行。
回车让打字机的打印头回到起始位置。 换行让打印头往下移动一行。观看视频

回车 CR。Carriage return。 Carriage是打字机的滑杠。但是它也有马车的意思,所以翻译成回车。
换行 LR。Line feed。字面意思 喂了一行,含义就是换行。
回车 CR,ASCII值是0x0D,13, 转义字符是\r。 (return)
换行 LF,ASCII值是0x0A,10, 转义字符是\n。 (new line)

2

到了计算机时代,沿袭了打字机的概念。
回车 光标回到行首 不换行。 换行 光标移动到下一行 不回到行首。
那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以,用一个字符来完成两个操作。于是,就出现了分歧。
unix 中,用\n 完成 回车和换行 的功能(虽然\n还叫回车,但完成了回车和换行)。 \r还是仅仅的回车,无换行。
macos 中,用\r 完成 回车和换行 的功能。 不过现在macos也转向了unix方式了。
windows中,维持传统,\r\n 才是回车和换行。 \r仅仅是回车,\n仅仅是换行。
(另外,注意, 在网络协议中还是用\r\n表示回车换行,比如http协议中头和数据之间的换行就是\r\n)

一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号,即多余的\r就用^M表示出来。(之所以显示为^M是因为Linux下一般用^表示Ctrl键,而Ctrl+M表示回车,可以在命令行里试试)

另一个后果 就是编程上的兼容性问题。
比如C语言对于文件中回车换行的处理。C标准库为了统一文件的回车换行,可以使用文本模式。
打开文件的方式分为两种:二进制模式和文本模式。
对于二进制模式,写入\r \n 原样写入, 读出\r \n 也是原样读出。
对于文本模式, 分系统。 对于windows,写入\n,会转成\r\n, 读出\r\n会转成 \n. 对于linux/macos, 写入\n,还是转成\n, 读出\n会转成\n(linux/unix/mac 下文本模式和二进制模式都一样的,都等同于二进制模式)。虽然在系统层面不一样,但是在c的层面统一了。 文本模式其实就是 在中间 加了一层,做了兼容处理。 (很多时候计算机问题,都能往上加一层后,解决问题。比如网络的七层模型等)
所以对于文本模式,实现回车 换行,统一使用\n。 对于二进制模式,还是要分系统分析,要做跨平台的处理。 对于C标准库中的标准输入 标准输出 标准错误 默认是文本模式的,因此printf(“\n”)在各个系统都是回车换行。

3

虽然我们日常只说 回车 或者 换行 或者 enter,但是实际都是指 回车和换行,即回到行首,并到下一行。

4

参考:
https://www.ruanyifeng.com/blog/2006/04/post_213.html
https://zhuanlan.zhihu.com/p/479064200

5 附录

在c中如何控制回车,换行,以及光标的移动。
参考:https://blog.csdn.net/yuhai738639/article/details/79221835
以下标准输入输出 其实都是在文本模式下。

  • 仅仅回车,未换行:
    #include <stdio.h>
    #include <unistd.h> 
    int main(){
    	for(int i = 0; i < 100; i++){
    		printf("process %4d \r", i); //回车 未换行。
    		fflush(stdout);//强制刷新缓存,输出显示
    		// usleep(200);
    		sleep(1);
    
    	}
    	return 0;
    }
  • 仅仅换行,不回车
    无。
  • 回车换行:(虽然\n还是叫回车,但是完成了回车和换行操作)
    \n
更多的参考可以 查看 笔记 C语言。