符号 | ASCII | 意义 |
\n | 0x0A | 换行(LF) |
\r | 0x0D | 回车(CR) |
\r 是return的简写,表示光标重新回到本行开头。其缩写CR是carriage return就是回车的意思。
\n 是new line的简写,表示光标垂直向下移动一行。其缩写LF是Line Feed就是换行的意思。
在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33,Linux/Unix下的tty概念也来自于此)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。
于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。
后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。
Unix系统里,每行结尾只有“<换行>”,即"\n";
Windows系统里面,每行结尾是“<换行><回车>”,即“\r\n”;
Mac系统里,每行结尾是“<回车>”,即"\n";。
一个直接后果是,Unix/Mac系统下的文件在 Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
于是,进行测试,分别在win10和ubuntu系统中新建文本文档写入两行文字:第一行为123456789,第二行为987654321。然后在win10系统中打开两个文本,发现win10自己创建的文件是分为两行显示的,没有问题。Ubuntu生成的文件在win10中显示为1行。接下来在Ubuntu中打开两个文件,发现两个文件均换行。接下来在win10系统中通过UltraEdit打开,查看两个文件的ASCII码,如下:
win10中生成的文件:
Ubuntu中生成的文件:
从结果可以看出,正如上面所说,Unix系统中,每行结尾只有”\n”;windows系统中每行结尾是”\r\n”。
还没结束,接下来说一说在C语言编程中的”\n”,因为这里与上面说的又有不同。
#include <stdio.h> #include <math.h> #include <stdio.h> FILE *fp; void main() { fp = fopen("p1.txt","wb"); fprintf(fp, "123456789\n987654321"); fclose(fp); return; }
如上代码,fopen函数中,参数"wb"表示只写打开或新建一个二进制文件;只允许写数据。根据上面所提到的\n意义,我们推断在win10中,打开生成的txt文件,应该仅输出一行。实际情况也确实如此。接下来,我们把fopen中的参数改为fopen("p1.txt","wx");其余代码全不变,这里"wx"表示创建文本文件,只允许写入数据。其结果发现生成的txt中,存在两行,也就是说"\n"一个符号就完成了win10中的换行命令。这说明在C语言中输出文档时,若采用二进制编码输出文件,函数会严格按照给定字符串的编码来进行输出;但是如果设定输出文档时以文本形式输出,函数会自动将\n解析为\r\n,从而输出两行文本。这一点在控制台程序中也有体现:
#include <stdio.h> void main() { printf("Hello World!\n"); }
上面的代码显然会换行,并在第二行输出:Press any key to continue
再啰嗦一些,如果把第一段代码中fprintf(fp, "123456789\n987654321");改为fprintf(fp, "123456789\r\n987654321");并且采用"wx"输出,会怎么样呢?
嗯!首先肯定是会换行的。然后,我们参看它的ASCII,发现\r\n在文本中并不是像预期的那样是0D 0A而是0D 0D 0A:
这也说明了,在这里代码中的"\n"被fprintf函数解析输出为"\r\n"。当然如果在linux系统下执行这个程序,应该是会把"\n"仅解析为"\n"的。
嗯,然后也可以测试一下fprintf(fp, "123456789\r987654321");在"wb"和"wx"情况下的输出文本结果。嗯是完全一样的:123456789987654321
但是,如果在控制台上输出结果,例如:printf("123456789\r987654321");实际输出结果为:987654321,说明"\r"起作用,控制台先输出123456789,然后,"\r"使光标移动到最前方,输出987654321,将原来的输出覆盖。