c++ 預處理和預處理命令
前處理器
預處理髮生在編譯之前,預處理輸出的是一個單一的檔案,這個檔案被送到編譯器,進行編譯。
預處理命令
每條預處理命令都控制前處理器的行為。每條預處理命令佔據一行,有以下的格式:
* # character
* 預處理命令(one of define, undef, include, if, ifdef, ifndef, else, elif, endif, line, error, pragma)
* 引數
* 換行符
條件編譯命令
預處理命令可以條件編譯源程式的某一部分。指令包括:
#if expression #ifdef expression #ifndef expression #elif expression #else #endif
expression must be const expression
Example
#define ABCD 2 #include <iostream> int main(){ #ifdef ABCD std::cout<<"1: yes\n"; #else std::cout<<"1: no\n"; #endif #ifndef ABCD std::cout<<"2: no1\n"; #elif ABCD==2 std::cout<<"2: yes\n"; #else std::cout << "2: no2\n"; #endif #if !defined(DSDE) && (ABCD < 2*4 - 3) std::cout<<"3: yes\n"; #endif } //output: //1: yes //2: yes //3: yes
替換文字巨集命令
語法:
#define identifier replacement-list(optional) (1)
#define identifier( parameters ) replacement-list (2)
#define identifier( parameters, ... ) replacement-list (3) (since C++11)
#define identifier( ... ) replacement-list (4) (since C++11)
#undef identifier (5)
#define
不能重複定義相同的巨集,否則,編譯會報錯。但是,如果重複定義的巨集完全相同,則,沒有任何問題。
object-like macro
(1)的形式。
function-like macro
(2)(3)(4)的形式
(2) 引數個數固定
(3)(4) 可變引數個數,引數能夠被訪問通過:VA_ARGS
# and ## operators
#被用在replacement-list 中,放在變數前,目的是字串化該變數。生成的結果是“...”。
#define showlist(...) puts(#__VA_ARGS__)
showlist(); // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")
##用來連線兩個identifier
#include <iostream>
#define FUNCTION(name, a) int fun_##name(){return a;}
FUNCTION(abcd, 12)
FUNCTION(fff, 2)
FUNCTION(qqq, 23)
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout<<#a<<std::endl;
int main()
{
std::cout << "abcd: " << fun_abcd() << '\n';
std::cout << "fff: " << fun_fff() << '\n';
std::cout << "qqq: " << fun_qqq() << '\n';
std::cout << FUNCTION << '\n';
OUTPUT(million); //note the lack of quotes
}
#include命令
include其他原始檔到當前檔案中,並且,放在該指令之後。語法:
#include <filename> (1)
#include "filename" (2)
#include 搜尋檔案的路徑為:standard include directories 。標準c庫和c++庫的目錄都被加入到了standard include directories。standard include directories 通常通過編譯選項來定義。如果在standard include directories沒有搜尋到該檔案,程式將會報錯。
#include "filename" 搜尋檔案的路徑為: 先在當前檔案所在目錄下搜尋,如果沒有搜尋到,將在standard include directories下搜尋。如果,都沒有搜尋到,程式報錯。
注意問題:
一個檔案可能被重複Include,或者遞迴地include, 為了避免這個問題,通常要在include的檔案中,加入一些預處理命令(通常是標頭檔案)。
#ifndef FOO_H_INCLUDED /* any name uniquely mapped to file name */
#define FOO_H_INCLUDED
// contents of the file are here
#endif
Example:
#ifndef TEXT
#define TEXT
#include __FILE__
int main(){
//如果不防止重複include該檔案,將會不停include檔案,程式ill
}
#endif
Error 命令
語法:
#error error_message
用於對編譯前的檢測,程式遇到error,就會停止編譯。
編譯器自定義指令
語法: #pragma pragma_paramsC++ 標準不包含這些指令,但是編譯器廠商會根據自己的需要,定義自己的指令。如果程式遇到不認識的#pragma指令,會直接跳過,不會報錯。
改變檔名和行號指令
語法:
#line lineno (1)
#line lineno "filename" (2)
改變指令之後的LINE變數和FILE變數。
#include <cassert>
#define FNAME "test.cc"
int main()
{
#line 777 FNAME
assert(2+2 == 5);
}
//output: test: test.cc:777: int main(): Assertion `2+2 == 5' failed.