C/C++的先行編譯和宏定義

來源:互聯網
上載者:User
文章目錄
  • 第一種條件編譯
  • 第二種條件編譯

先行編譯是整個編譯過程的第一步,是g++ -E選項輸出的結果。

這個步驟處理的是源檔案/標頭檔中的宏,巨集指令常用的有以下幾類:

  • 檔案包含:#include
  • 宏定義:#define、#undef
  • 條件編譯:#ifdef、#ifndef、#if、#elif、#else、#endif
1. 檔案包含 #include

預先處理會把要包含的檔案的內容全部包含進來,比如下面這個檔案prepro.cpp:

#include "prehead.h"int main(){  add(1, 2);}

引入了標頭檔prehead.h:

#ifndef _PREHEAD_H#define _PREHEAD_H/* declaration of a function that add two integer */int add(int, int);#endif

使用命令g++ -E prepro.cpp先行編譯,輸出結果如下:

# 1 "prepro.cpp"# 1 "<built-in>"# 1 "<command-line>"# 1 "prepro.cpp"# 1 "prehead.h" 1int add(int, int);# 2 "prepro.cpp" 2int main(){  add(1, 2);}

可以看到結果中兩個檔案的宏定義都被刪除了,檔案prehead.h中注釋也被刪除了,而剩下的內容被引入了prepro.h中。至於#ifndef的意思最後介紹。

2. 宏定義:#define、#undef

#define宏定義的一種用法是聲明一個宏,用來實現條件編譯,這種用法後面和#ifdef等宏命令一起介紹。

#define宏定義的另一種用法是用來定義常量,定義准inline的函數。這種用法不好,應該避免使用。

使用#define定義的變數,比如:#define PI 3.14,先行編譯以後程式中所有的PI都會被3.14替代。再比如上次談g++那篇部落格的這個例子:

#define ONE 1#define TWO 2int add_one_two(){  return ONE + TWO;}

先行編譯後結果如下:

# 1 "add.cpp"# 1 "<built-in>"# 1 "<command-line>"# 1 "add.cpp"int add_one_two(){  return 1 + 2;}

可以看到定義的ONE被替換成了1,定義的TWO被替換成了2。

使用常量是好的,但是使用#define這種方法的不好是調試時候變數名都被替換了,失去了常量的效果。最好用下面這種方式定義變數:

const TYPE VAR_NAME=value

使用#define定義准inline函數,比如下面這個的例子(引自《effective C++》):

#define max(a, b) ( (a) > (b) ? (a) : (b) )

一般也沒什麼問題,但是:

int a = 5, b = 0;max(++a, b);/* a自增了兩次 */max(++a, b + 10);/* b自增了一次*/

所以這樣定義是會出問題的。使用#define定義函數的初衷是為了提高程式運行速度,但是這種方式提高速度有限,根本上應該從改進資料結構,演算法方面入手。這種#define,果斷寫成inline就OK了,那麼多括弧寫著累,看著也累,沒必要。

3. 條件編譯:#ifdef、#ifndef、#if、#elif、#else、#endif

條件編譯算是宏最精髓的應用吧。先來說說這幾個指令的意思,如果你看過我前面的部落格,而且堅持在USACO上做題,那麼想必你已經熟悉了C++最基本的文法,那這幾個指令看一眼也能基本知道大概意思。下面用注釋方式解釋:

#ifdef//if define,如果定義了。。。#ifndef//if not define,如果沒有定義。。。#if// 如果。。。#elif// 或者如果。。。#else// 或者。。。#endif// 結束if
第一種條件編譯

用來防止一個標頭檔引入兩次。比如開始那個例子裡面的標頭檔prehead.h:

#ifndef _PREHEAD_H/* 如果沒有定義_PREHEAD_H */#define _PREHEAD_H/* 定義_PREHEAD_H *//* declaration of a function that add two integer */int add(int, int);#endif                         /* 結束上面對應的#ifndef */

然後更改下我們的prepro.cpp檔案,增加一行#include "prehead.h"

#include "prehead.h"#include "prehead.h"int main(){  add(1, 2);}

這裡我手工展開,變成下面這個樣子,然後在注釋裡面分析一下:

#ifndef _PREHEAD_H/* 如果沒有定義_PREHEAD_H */  /* 的確沒有定義 */#define _PREHEAD_H/* 定義_PREHEAD_H */  /* 那麼就定義之 *//* declaration of a function that add two integer */int add(int, int);#endif                         /* 結束上面對應的#ifndef */#ifndef _PREHEAD_H/* 如果沒有定義_PREHEAD_H */  /* 上面已經定義了,條件為false */#define _PREHEAD_H/* 定義_PREHEAD_H */  /* 所以從這裡開始到endif都會被前置處理器刪除 *//* declaration of a function that add two integer */int add(int, int);#endif                         /* 結束上面對應的#ifndef */  /* 後面的編譯獨立於第二個#ifndef _PREHEAD_H */int main(){  add(1, 2);}

使用命令g++ -E prepro.cpp,輸出和第一個例子裡面一樣,如下:

# 1 "prepro.cpp"# 1 "<built-in>"# 1 "<command-line>"# 1 "prepro.cpp"# 1 "prehead.h" 1int add(int, int);# 2 "prepro.cpp" 2int main(){  add(1, 2);}

或許你會說,這個SB,一個標頭檔include兩次,哈哈哈哈。但是,這隻是個例子,實際項目中檔案引入比較複雜,比如上面的prepro.cpp引入了第三個檔案,然後第三個檔案引入prehead.h,那麼沒有條件編譯的話prepro.cpp裡面就會有兩個prehead.h。

使用#ifndef... #define... #endif可以保證一個檔案只引入一次,這裡的...可以是任何內容,只要你能保證定義的這個東西其他地方沒定義,但是慣例是定義檔案名稱的大寫然後加幾個底線,像上面那個例子一樣。

第二種條件編譯

用來實現跨平台編譯。比如下面這樣:

#ifdef _linux_// linux平台相關代碼。。。#endif#ifdef _windows_// windows平台相關代碼。。。#endif#ifdef _macos_// mac os平台相關代碼#endif

然後在某個include的設定檔config.h裡面,如果有如下定義:#define _linux_,那麼編譯器就只編譯linux平台相關的代碼;如果有如下定義:#define _windows_,那麼只編譯windows平台相關的代碼。

最後要說明的是,設定檔config.h不是手動寫的,而是指令碼自動產生的。至於如何編寫指令碼或者使用工具產生指令碼,算是另一個話題了,以後再介紹吧。

巨集指令還有其他一些,但是用的很少,我就不寫了,想瞭解的朋友可以參考這個網址:點擊進入。這個網站C++的文檔,手冊,協助都一流,學習C++可以多看看。

參考文獻:

Effective C++, third edition. Scott Meyers. 2005

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.