位置:首頁 > 高級語言 > C語言教學 > C語言預處理器

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