1. 預處理的步驟

現在我們全面瞭解一下C編譯器做語法解析之前的預處理步驟:

1、把第 2 節 “常量”提到過的三連符替換成相應的單字元。

2、把用\字元續行的多行代碼接成一行。例如:

#define STR "hello, "\
		"world"

經過這個預處理步驟之後接成一行:

#define STR "hello, "		"world"

這種續行的寫法要求\後面緊跟換行,中間不能有其它空白字元。

3、把註釋(不管是單行註釋還是多行註釋)都替換成一個空格。

4、經過以上兩步之後去掉了一些換行,有的換行在續行過程中去掉了,有的換行在多行註釋之中,也隨着註釋一起去掉了,剩下的代碼行稱為邏輯代碼行。然後預處理器把邏輯代碼行劃分成Token和空白字元,這時的Token稱為預處理Token,包括標識符、整數常量、浮點數常量、字元常量、字元串、運算符和其它符號。繼續上面的例子,兩個原始碼行被接成一個邏輯代碼行,然後這個邏輯代碼行被劃分成Token和空白字元:#define,空格,STR,空格,"hello, ",Tab,Tab,"world"

5、在Token中識別出預處理指示,做相應的預處理動作,如果遇到#include預處理指示,則把相應的源檔案包含進來,並對源檔案做以上1-4步預處理。如果遇到宏定義則做宏展開。

我們早在第 2 節 “數組應用實例:統計隨機數”就認識了預處理指示這個概念,現在給出它的嚴格定義。一條預處理指示由一個邏輯代碼行組成,以#開頭,後面跟若干個預處理Token,在預處理指示中允許使用的空白字元只有空格和Tab。

6、找出字元常量或字元串中的轉義序列,用相應的位元組來替換它,比如把\n替換成位元組0x0a。

7、把相鄰的字元串連接起來。繼續上面的例子,如果代碼中有:

printf(
	STR);

經過第4步處理劃分成以下Token:printf(,換行,Tab,STR);,換行。經過第5步宏展開後變成以下Token:printf(,換行,Tab,"hello, ",Tab,Tab,"world");,換行。然後把相鄰的字元串連接起來,變成以下Token:printf(,換行,Tab,"hello, world");,換行。

8、經過以上處理之後,把空白字元丟掉,把Token交給C編譯器做語法解析,這時就不再是預處理Token,而稱為C Token了。這裡丟掉的空白字元包括空格、換行、水平Tab、垂直Tab、分頁符。繼續上面的例子,最後交給C編譯器做語法解析的Token是:printf("hello, world");。注意,把一個預處理指示寫成多行要用\續行,因為根據定義,一條預處理指示只能由一個邏輯代碼行組成,而把C代碼寫成多行則不需要用\續行,因為換行在C代碼中只不過是一種空白字元,在做語法解析時所有空白字元都已經丟掉了。