1. 程式人生 > >c++ 預處理和預處理命令

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.