C語言宏基礎總結

最近在作一些項目的時候,不當心把NDK下面的一些宏寫得有問題,致使一些編譯不過的問題。因此,總結一下。
這些知識均可以在 GCC 文檔上找到,本文主要參考博文《C語言宏的特殊用法和幾個坑》html

基礎

(1) 標示符別名git

#define PI 3.14159

在預處理階段:pi = PI結果是pi=3.14159;github

(2)宏函數
宏名以後帶括號的宏被認爲是宏函數。用法和普通函數同樣,只不過在預處理階段,宏函數會被展開。優勢是沒有普通函數保存寄存器和參數傳遞的開銷,展開後的代碼有利於CPU cache的利用和指令預測,速度快。缺點是可執行代碼體積大。函數

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))

y = min(1, 2);會被擴展成y = ((1) < (2) ? (1) : (2));post

宏特殊用法

(1)字符串化(Stringification)
在宏體中,若是宏參數前加個#,那麼在宏體擴展的時候,宏參數會被擴展成字符串的形式.如:ui

#define WARN_IF(EXP) \
     do { if (EXP) \
             fprintf (stderr, "Warning: " #EXP "\n"); } \
     while (0)

調用是使用WARN_IF (x == 0);會被擴展成:code

do { if (x == 0)
    fprintf (stderr, "Warning: " "x == 0" "\n"); }
while (0);

這種用法能夠用在assert中,若是斷言失敗,能夠將失敗的語句輸出到反饋信息中。htm

(2) 鏈接(Concatenation)
在宏體中,若是宏體所在標示符中有##,那麼在宏體擴展的時候,宏參數會被直接替換到標示符中。如:文檔

#define COMMAND(NAME)  { #NAME, NAME ## _command }

struct command
{
    char *name;
    void (*function) (void);
};

在宏擴展的時候字符串

struct command commands[] =
{
    COMMAND (quit),
    COMMAND (help),
    ...
};

會被擴展成:

struct command commands[] =
{
    { "quit", quit_command },
    { "help", help_command },
    ...
};

注意事項:

  • 預處理器採起的策略是只展開一次, 如定義下面的宏:
#define foo (4 + foo)

交叉引用,宏體也只會展開一次,foo只會展開成(4 + foo),而展開以後foo的含義就要根據上下文來肯定了。

  • 宏參數中若包含另外的宏,那麼宏參數在被代入到宏體以前會作一次徹底的展開,除非宏體中含有#或##
相關文章
相關標籤/搜索