C語言預處理器
C語言預處理程序是不是編譯器的一部分,隻不過在編譯過程中的一個單獨的步驟。在簡單來說,C語言預處理器隻是一個文本替換工具,它們指示編譯器實際編譯之前需要做預處理。我們參考C語言預處理器如CPP。
所有的預處理命令以一個井號(#)。它必須是第一個非空字符,並且為便於閱讀,一個預處理指令應該開始第一列。以下部分列出了所有重要的預處理指令:
指令 | 描述 |
---|---|
#define | 替代預處理宏 |
#include | 從另一個文件中插入一個特殊的頭 |
#undef | 取消定義預處理宏 |
#ifdef | 返回true,如果這個宏定義 |
#ifndef | 返回true,如果該宏冇有被定義 |
#if | 測試是否編譯時條件為true |
#else | 用於可選#if |
#elif | #else 一個 #if 在一條語句 |
#endif | 結束預處理條件 |
#error | stderr上打印錯誤信息 |
#pragma | 問題特殊命令給編譯器,使用一個標準化的方法 |
預處理程序示例
分析下麵的實施例來理解各種指令。
#define MAX_ARRAY_LENGTH 20
這個指令告訴CPP更換MAX_ARRAY_LENGTH實例使用值為20,使用#define定義的常量以增加可讀性。
#include <stdio.h> #include "myheader.h"
這些指令告訴CPP從係統庫得到stdio.h中的文本添加到當前的源文件。下一行告訴CPP獲得myheader.h從本地目錄和內容添加到當前的源文件。
#undef FILE_SIZE #define FILE_SIZE 42
這告訴CPP取消現有FILE_SIZE定義,並把它定義為42。
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
這告訴CPP定義隻有在MESSAGE尚未定義時,定義MESSAGE。
#ifdef DEBUG /* Your debugging statements here */ #endif
這告訴CPP執行過程中,DEBUG是否被定義在語句包圍內。如果通過-DDEBUG標誌gcc編譯器在編譯的時候是非常有用的。這將定義DEBUG,這樣就可以在編譯過程中打開和關閉調試。
預定義宏
ANSI C定義了許多宏。雖然每一個都可以在編程的使用中,預定義的宏不應直接修改。
宏 | 描述 |
---|---|
__DATE__ | 當前日期作為字符文字“MMM DD YYYY”格式 |
__TIME__ | 當前時間作為一個字符文字的“HH:MM:SS”格式 |
__FILE__ | 這包含了當前的文件名作為一個字符串 |
__LINE__ | 這包含當前行號為十進製常數 |
__STDC__ | 定義為1時,編譯器符合ANSI標準 |
讓我們來試試下麵的例子:
#include <stdio.h> main() { printf("File :%s ", __FILE__ ); printf("Date :%s ", __DATE__ ); printf("Time :%s ", __TIME__ ); printf("Line :%d ", __LINE__ ); printf("ANSI :%d ", __STDC__ ); }
當在一個文件test.c的上述代碼被編譯和執行時,它產生了以下結果:
File :test.c Date :Jun 2 2012 Time :03:36:24 Line :8 ANSI :1
預處理器運算符
C預處理器提供以下運算符,以幫助創建宏:
宏延續 ()
宏通常必須包含在一行。宏延續運算符用於繼續宏太長了的一行。例如:
#define message_for(a, b) printf(#a " and " #b ": We love you! ")
字符串大小 (#)
字符串大小或數字符號運算符('#'),當在宏定義中使用,將一個宏參數字符串常量。此運算符可使用僅在具有特定的參數或參數列表的宏。例如:
#include <stdio.h> #define message_for(a, b) printf(#a " and " #b ": We love you! ") int main(void) { message_for(Carole, Debra); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
Carole and Debra: We love you!
令牌粘貼 (##)
令牌粘貼運算符(##)中的宏定義結合了兩個參數。它允許在宏定義兩個獨立的令牌被加入到一個單一的令牌。例如:
#include <stdio.h> #define tokenpaster(n) printf ("token" #n " = %d", token##n) int main(void) { int token34 = 40; tokenpaster(34); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
token34 = 40
它是如何發生的,因為這個例子將從預處理器的實際輸出結果如下:
printf ("token34 = %d", token34);
這個例子顯示了令牌 ##n為進令牌34,在這裡我們使用了兩個字符串和令牌粘貼拚接。
defined() 操作符
預處理器定義的運算符采用的是常量表達式,以確定是否一個標識符使用#define定義。如果指定的標識符被定義,則該值是真(非零)。如果符號冇有定義,值為false(零)。定義的運算符規定如下:
#include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { printf("Here is the message: %s ", MESSAGE); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
Here is the message: You wish!
參數宏
CPP其中的一個強大的功能是模擬使用參數化的宏功能的能力。例如,我們可能有一些代碼方數如下:
int square(int x) { return x * x; }
我們可以使用宏如下改寫上麵的代碼:
#define square(x) ((x) * (x))
宏帶參數必須使用#define指令可以在使用之前進行定義。參數列表被括號括起來,而且必須緊跟在宏名。空格在宏觀名和左括號之間不允許的。例如:
#include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf("Max between 20 and 10 is %d ", MAX(10, 20)); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
Max between 20 and 10 is 20