預處理器是一些指令,指示表一起在實際編譯之前所需要完成的預處理。
所有的預處理器指令都是以井號(#)開頭,只有空格字符可以出現在預指令處理之前。預處理指令不是C++語句,所以他們不會以分號(;)結尾。
?
#define預處理
#define預處理指令用于創建符號常量。該符號常量通常稱之為宏,指令的一般行為為
#define macro-name replacement-text
當這行代碼出現在一個文件中,在該文件中后續出現的所有宏都會在程序編譯之前被替換成成replacement-text。
/*** define.cpp ***/ #include<iostream> using namespace std;#define PI 3.14159int main() {cout << "Value of PI :" << PI << endl;return 0; }
使用-E選項進行編譯,并把結果重定向到define.p 現在查看一下相關信息:
exbot@ubuntu:~/wangqinghe/C++/20190816$ gcc -E define.cpp > define.p
條件編譯
有幾個指令可以用來有選擇地對部分程序源代碼進行編譯,這個過程稱之為條件編譯。
條件預處理器地結構與if選擇結構很像。
#ifdef NULL#define NULL 0 #denif
在調試時進行編譯,調試開關可以使用一個宏來實現
#ifdef DEBUGcerr << “Variable x = ” << x << endl; #endif
如果在指令 #ifdef DEBUF 之前定義了符號常量,則會對程序中cerr語句進行編譯。可以使用 #if 0 語句注釋掉程序的一部分。
#if 0 不進行編譯的代碼 #endif
實例:
/*** ifdef.cpp ***/ #include<iostream> using namespace std; #define DEBUG#define MIN(a,b) (((a) < (b)) ? a : b)int main() {int i,j;i = 100;j = 20; #ifdef DEBUGcerr << "Trace: Inside main function" << endl; #endif#if 0cout << "MKSTR(HELLO C++)" << endl; #endifcout << "The minimum is " << MIN(i,j) << endl;#ifdef DEBUGcerr << "Trace: Comint out of main function" << endl; #endifreturn 0; }
運行結果:
exbot@ubuntu:~/wangqinghe/C++/20190816$ g++ ifdef.cpp -o ifdef
exbot@ubuntu:~/wangqinghe/C++/20190816$ ./ifdef
Trace: Inside main function
The minimum is 20
Trace: Comint out of main function
#和##運算符
#和##預處理運算符在C++和ANSI/ISO C中都是可用的
#運算符會把repalcement-text令牌轉換成引號引起來的字符串
/*** pound.cpp ***/ #include<iostream> using namespace std;#define MKSTR(x) #xint main() {cout << MKSTR(HELLO C++) << endl;return 0; }
運行結果:
exbot@ubuntu:~/wangqinghe/C++/20190816$ g++ pound.cpp -o pound
exbot@ubuntu:~/wangqinghe/C++/20190816$ ./pound
HELLO C++
?
C++預處理器把下面這行
cout << MKSTR(HELLO C++) << endl;
轉化成了:
cout << “HELLO C++” << endl;
##運算符用于連接兩個令牌
#define CONCAT(x,y) x ## y
當CONCAT出現在程序中,他的參數機會被連接起來,并用來取代宏,程序中CONCAT(HELLO C++)會被替換成“HELLO C++”如下圖:
/*** concat.cpp ***/ #include<iostream> using namespace std;#define concat(a,b) a##b int main() {int xy = 100;cout << concat(x,y) << endl;return 0; }
運行結果:
exbot@ubuntu:~/wangqinghe/C++/20190816$ g++ concat.cpp -o concat
exbot@ubuntu:~/wangqinghe/C++/20190816$ ./concat
100
?
C++預處理器把下面這行:
cout << concat(x,y) << endl;
轉化成了:
cout << xy;
C++中的預定義宏
?
C++提供了下表所示的一些預定義宏:
宏 | 描述 |
__LINE__ | 這會在編譯時包含當前行號 |
__FILE__ | 這會在編譯時包含當前文件名 |
__DATA__ | 這會包含一個形式為month/day/year的字符串,它表示把源文件轉換成目標代碼的日期 |
__TIME__ | 這會包含一個形式為hour:minute:second的字符串,它表示程序被編譯的時間 |
?
實例:
/*** macro.cpp ***/ #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; }
運行結果:
exbot@ubuntu:~/wangqinghe/C++/20190816$ g++ macro.cpp -o macro
exbot@ubuntu:~/wangqinghe/C++/20190816$ ./macro
Value of __LINE__ :6
Value of __FILE__ :macro.cpp
Value of __DATE__ :Aug 16 2019
Value of __TIME__ :14:06:20
# 和 ## 運算符
# 字符串化的意思,出現在宏定義中的#是把跟在后面的參數轉換成一個字符串。
當用作字符串化操作時,# 的主要作用是將宏參數不經擴展地轉換成字符串常量。
?宏定義參數的左右兩邊的空格會被忽略,參數的各個 Token 之間的多個空格會被轉換成一個空格。
?宏定義參數中含有需要特殊含義字符如"或\時,它們前面會自動被加上轉義字符 \。
## 連接符號,把參數連在一起。
將多個 Token 連接成一個 Token。要點:
?
?它不能是宏定義中的第一個或最后一個 Token。
?前后的空格可有可無。
?