C++ 預處理器



預處理器是指令,它們指示編譯器在實際編譯開始之前預處理資訊。

所有預處理器指令都以 # 開頭,一行預處理器指令之前只能出現空格字元。預處理器指令不是 C++ 語句,因此它們不以分號 (;) 結尾。

您已經在所有示例中看到了 #include 指令。此宏用於將標頭檔案包含到原始檔中。

C++ 支援許多預處理器指令,例如 #include、#define、#if、#else、#line 等。讓我們看看重要的指令:

#define 預處理器

#define 預處理器指令建立符號常量。符號常量稱為,指令的一般形式為:

#define macro-name replacement-text 

當此行出現在檔案中時,該檔案中宏的所有後續出現都將在程式編譯之前替換為 replacement-text。例如:

#include <iostream>
using namespace std;

#define PI 3.14159

int main () {
   cout << "Value of PI :" << PI << endl; 

   return 0;
}

現在,讓我們對這段程式碼進行預處理以檢視結果,假設我們有原始碼檔案。因此,讓我們使用 -E 選項進行編譯並將結果重定向到 test.p。現在,如果您檢查 test.p,它將包含大量資訊,並且在底部,您會發現值替換如下:

$gcc -E test.cpp > test.p

...
int main () {
   cout << "Value of PI :" << 3.14159 << endl; 
   return 0;
}

類函式宏

您可以使用 #define 來定義一個宏,它將採用如下引數:

#include <iostream>
using namespace std;

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;
   
   cout <<"The minimum is " << MIN(i, j) << endl;

   return 0;
}

如果我們編譯並執行上面的程式碼,這將產生以下結果:

The minimum is 30

條件編譯

有幾個指令可以用來編譯程式原始碼的選擇部分。此過程稱為條件編譯。

條件預處理器構造很像“if”選擇結構。考慮以下預處理器程式碼:

#ifndef NULL
   #define NULL 0
#endif

您可以編譯程式以進行除錯。您還可以使用單個宏開啟或關閉除錯,如下所示:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

如果在 #ifdef DEBUG 指令之前已定義符號常量 DEBUG,這將導致cerr 語句在程式中編譯。您可以使用 #if 0 語句註釋掉程式的一部分,如下所示:

#if 0
   code prevented from compiling
#endif

讓我們嘗試以下示例:

#include <iostream>
using namespace std;
#define DEBUG

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;

#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif

#if 0
   /* This is commented part */
   cout << MKSTR(HELLO C++) << endl;
#endif

   cout <<"The minimum is " << MIN(i, j) << endl;

#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif

   return 0;
}

如果我們編譯並執行上面的程式碼,這將產生以下結果:

The minimum is 30
Trace: Inside main function
Trace: Coming out of main function

# 和 ## 運算子

# 和 ## 預處理器運算子在 C++ 和 ANSI/ISO C 中可用。 # 運算子導致將 replacement-text 令牌轉換為用引號括起來的字串。

考慮以下宏定義:

#include <iostream>
using namespace std;

#define MKSTR( x ) #x

int main () {

   cout << MKSTR(HELLO C++) << endl;

   return 0;
}

如果我們編譯並執行上面的程式碼,這將產生以下結果:

HELLO C++

讓我們看看它是如何工作的。很容易理解 C++ 預處理器如何將以下行:

cout << MKSTR(HELLO C++) << endl;

上面的行將轉換為以下行:

cout << "HELLO C++" << endl;

## 運算子用於連線兩個令牌。這是一個示例:

#define CONCAT( x, y )  x ## y

當 CONCAT 出現在程式中時,它的引數將被連線起來並用於替換宏。例如,CONCAT(HELLO, C++) 在程式中將替換為“HELLO C++”,如下所示。

#include <iostream>
using namespace std;

#define concat(a, b) a ## b
int main() {
   int xy = 100;
   
   cout << concat(x, y);
   return 0;
}

如果我們編譯並執行上面的程式碼,這將產生以下結果:

100

讓我們看看它是如何工作的。很容易理解 C++ 預處理器如何轉換以下行:

cout << concat(x, y);

上面的行將轉換為以下行:

cout << xy;

預定義的 C++ 宏

C++ 提供了許多下面提到的預定義宏:

序號 宏和描述
1

__LINE__

這包含程式在編譯時的當前行號。

2

__FILE__

這包含程式在編譯時的當前檔名。

3

__DATE__

這包含一個“月/日/年”形式的字串,即原始檔轉換為目的碼的日期。

4

__TIME__

這包含一個“小時:分鐘:秒”形式的字串,即編譯程式的時間。

讓我們看看上面所有宏的示例:

#include <iostream>
using namespace std;

int main () {
   cout << "Value of __LINE__ : " << __LINE__ << endl;
   cout << "Value of __FILE__ : " << __FILE__ << endl;
   cout << "Value of __DATE__ : " << __DATE__ << endl;
   cout << "Value of __TIME__ : " << __TIME__ << endl;

   return 0;
}

如果我們編譯並執行上面的程式碼,這將產生以下結果:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48
廣告