符號 | 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,將原來的輸出覆蓋。