C語言預處理器



C預處理器不是編譯器的一部分,而是編譯過程中的一個單獨步驟。簡單來說,C預處理器只是一個文字替換工具,它指示編譯器在實際編譯之前進行必要的預處理。我們將C預處理器稱為CPP。

在C程式設計中,預處理是C程式碼編譯的第一步。它發生在詞法分析步驟之前。預處理器的重要功能之一是包含包含程式中使用的庫函式的標頭檔案。C語言中的預處理器還定義常量並展開宏。

C語言中的預處理器語句稱為指令。程式的預處理器部分始終出現在C程式碼的頂部。每個預處理器語句都以井號(#)符號開頭。

C語言中的預處理器指令

下表列出了所有重要的預處理器指令:

指令 描述
# define 替換預處理器宏。
#include 插入來自另一個檔案的特定標頭檔案。
#undef 取消定義預處理器宏。
#ifdef 如果此宏已定義,則返回true。
#ifndef 如果此宏未定義,則返回true。
#if 測試編譯時條件是否為真。
#else #if 的替代方案。
#elif #else 和 #if 合併成一個語句。
#endif 結束預處理器條件。
#error 在stderr上列印錯誤訊息。
#pragma 使用標準化的方法向編譯器發出特殊命令。

預處理器示例

分析以下示例以瞭解各種指令。

#define指令告訴CPP將MAX_ARRAY_LENGTH的所有例項替換為20。使用#define定義常量以提高可讀性。

#define MAX_ARRAY_LENGTH 20

以下指令告訴CPP從系統庫中獲取“stdio.h”並將文字新增到當前原始檔中。下一行告訴CPP從本地目錄獲取“myheader.h”並將內容新增到當前原始檔中。

#include <stdio.h>
#include "myheader.h"

現在,讓我們看一下以下#define和#undef指令。它們告訴CPP取消定義現有的FILE_SIZE並將其定義為42。

#undef  FILE_SIZE
#define FILE_SIZE 42

以下指令告訴CPP僅在MESSAGE未定義時定義MESSAGE。

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

以下指令告訴CPP如果定義了DEBUG,則處理包含的語句。

#ifdef DEBUG
   /* Your debugging statements here */
#endif

如果您在編譯時向gcc編譯器傳遞-DDEBUG標誌,這將很有用。這將定義DEBUG,因此您可以在編譯過程中動態地開啟和關閉除錯。

C語言中的預定義宏

ANSI C定義了許多宏。儘管每個宏都可用於程式設計,但不應直接修改預定義宏。

描述
__DATE__ 當前日期,以“MMM DD YYYY”格式的字元字面量表示。
__TIME__ 當前時間,以“HH:MM:SS”格式的字元字面量表示。
__FILE__ 包含當前檔名,作為字串字面量。
__LINE__ 包含當前行號,作為十進位制常量。
__STDC__ 當編譯器符合ANSI標準時定義為1。

示例

讓我們嘗試以下示例:

#include <stdio.h>

int main(){

   printf("File: %s\n", __FILE__ );
   printf("Date: %s\n", __DATE__ );
   printf("Time: %s\n", __TIME__ );
   printf("Line: %d\n", __LINE__ );
   printf("ANSI: %d\n", __STDC__ );
}

輸出

執行此程式碼時,將產生以下輸出:

File: main.c
Date: Mar 6 2024
Time: 13:32:30
Line: 8
ANSI: 1

預處理器運算子

C預處理器提供以下運算子來幫助建立宏:

示例:C語言中的宏續接符(\)運算子

宏通常限制在一行內。宏續接符(\)用於繼續過長而無法在一行中容納的宏。請看下面的例子:

#include <stdio.h>

#define message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

int main() {
   message_for(Ram, Raju);
}

輸出

執行此程式碼時,將產生以下輸出:

Ram and Raju: We love you!

示例:C語言中的字串化(#)運算子

字串化運算子(#),也稱為井號運算子,在宏定義中使用時,會將宏引數轉換為字串常量。

字串化運算子只能用於具有指定引數列表的宏。例如:

#include <stdio.h>

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

int main() {

   message_for(Carole, Debra);
   return 0;
}

輸出

執行程式碼並檢查其輸出:

Carole and Debra: We love you!

示例:C語言中的標記貼上(##)運算子

宏定義中的標記貼上運算子(##)組合兩個引數。它允許宏定義中的兩個單獨標記連線成一個標記。例如:

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main() {

   int token34 = 40;
   tokenpaster(34);
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出:

token34 = 40

示例:C語言中的defined()運算子

預處理器defined運算子用於常量表達式中,以確定是否使用#define定義了識別符號。如果指定了識別符號,則值為true(非零)。如果符號未定義,則值為false(零)。

以下示例演示如何在C程式中使用defined運算子

#include <stdio.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main() {

   printf("Here is the message: %s\n", MESSAGE);  
   return 0;
}

輸出

執行程式碼並檢查其輸出:

Here is the message: You wish!

C語言中的引數化宏

CPP的強大功能之一是能夠使用引數化宏來模擬函式。例如,我們可能有如下計算平方數的程式碼:

int square(int x) {
   return x * x;
}

我們可以使用宏重寫上述程式碼,如下所示:

#define square(x) ((x) * (x))

帶引數的宏必須在使用之前使用#define指令定義。引數列表括在括號中,並且必須緊跟在宏名之後。宏名和左括號之間不允許有空格。

示例

以下示例演示如何在C語言中使用引數化宏:

#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main() {

   printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出:

Max between 20 and 10 is 20
廣告