C語言 條件編譯詳解

     指令             用途
         #           空指令,無任何效果
         #include    包含一個源代碼文件
         #define     定義宏
         #undef      取消已定義的宏
         #if         如果給定條件爲真,則編譯下面代碼
         #ifdef      如果宏已經定義,則編譯下面代碼
         #ifndef     如果宏沒有定義,則編譯下面代碼
         #elif       如果前面的#if給定條件不爲真,當前條件爲真,則編譯下面代碼
         #endif      結束一個#if……#else條件編譯塊
         #error      停止編譯並顯示錯誤信息
一、文件包含
       爲了避免那些只能包含一次的頭文件被多次包含,可以在頭文件中用編譯時條件來進行控制。例如:
       
        #ifndef MY_H
        #define MY_H
          ……
        #endif


二、宏
   
    1.#define指令
        #define預處理指令是用來定義宏的。該指令最簡單的格式是:首先神明一個標識符,然後給出這個標識符代表的代碼。在後面的源代碼中,就用這些代碼來替代該標識符。這種宏把程序中要用到的一些全局值提取出來,賦給一些記憶標識符。
            #define MAX_NUM 10
            int array[MAX_NUM];
            for(i=0;i<MAX_NUM;i++) 
        
         在這個例子中,對於閱讀該程序的人來說,符號MAX_NUM就有特定的含義,它代表的值給出了數組所能容納的最大元素數目。程序中可以多次使用這個值。作爲一種約定,習慣上總是全部用大寫字母來定義宏,這樣易於把程序紅的宏標識符和一般變量標識符區別開來。如果想要改變數組的大小,只需要更改宏定義並重新編譯程序即可。
        宏表示的值可以是一個常量表達式,其中允許包括前面已經定義的宏標識符。例如:
            #define ONE 1
            #define TWO 2
            #define THREE (ONE+TWO)
        注意上面的宏定義使用了括號。儘管它們並不是必須的。但出於謹慎考慮,還是應該加上括號的。例如:
            six=THREE*TWO;
        預處理過程把上面的一行代碼轉換成:
            six=(ONE+TWO)*TWO;
        如果沒有那個括號,就轉換成six=ONE+TWO*TWO;了。
        宏還可以代表一個字符串常量,例如:
            #define VERSION "Version 1.0 Copyright(c) 2003"
    2.帶參數的#define指令
        帶參數的宏和函數調用看起來有些相似。看一個例子:
            #define Cube(x) (x)*(x)*(x)
        可以時任何數字表達式甚至函數調用來代替參數x。這裏再次提醒大家注意括號的使用。宏展開後完全包含在一對括號中,而且參數也包含在括號中,這樣就保證了宏和參數的完整性。看一個用法:
            int num=8+2;
            volume=Cube(num);
        展開後爲(8+2)*(8+2)*(8+2);
        如果沒有那些括號就變爲8+2*8+2*8+2了。
        下面的用法是不安全的:
            volume=Cube(num++);
        如果Cube是一個函數,上面的寫法是可以理解的。但是,因爲Cube是一個宏,所以會產生副作用。這裏的擦書不是簡單的表達式,它們將產生意想不到的結果。它們展開後是這樣的:
            volume=(num++)*(num++)*(num++);
        很顯然,結果是10*11*12,而不是10*10*10;
        那麼怎樣安全的使用Cube宏呢?必須把可能產生副作用的操作移到宏調用的外面進行:
            int num=8+2;
            volume=Cube(num);
            num++;
    3.#運算符
        出現在宏定義中的#運算符把跟在其後的參數轉換成一個字符串。有時把這種用法的#稱爲字符串化運算符。例如:
            #define PASTE(n) "adhfkj"#n
            main()
            {
               printf("%s\n",PASTE(15));
            }
        宏定義中的#運算符告訴預處理程序,把源代碼中任何傳遞給該宏的參數轉換成一個字符串。所以輸出應該是adhfkj15。
    4.##運算符
        ##運算符用於把參數連接到一起。預處理程序把出現在##兩側的參數合併成一個符號。看下面的例子:
            #define NUM(a,b,c) a##b##c
            #define STR(a,b,c) a##b##c
            main()
            {
                printf("%d\n",NUM(1,2,3));
                printf("%s\n",STR("aa","bb","cc"));
            }
        最後程序的輸出爲:
                 123
                 aabbcc
        千萬別擔心,除非需要或者宏的用法恰好和手頭的工作相關,否則很少有程序員會知道##運算符。絕大多數程序員從來沒用過它。
三、條件編譯指令
    條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的。可以根據表達式的值或者某個特定的宏是否被定義來確定編譯條件。
    1.#if指令
        #if指令檢測跟在製造另關鍵字後的常量表達式。如果表達式爲真,則編譯後面的代碼,知道出現#else、#elif或#endif爲止;否則就不編譯。
    2.#endif指令
        #endif用於終止#if預處理指令。
            #define DEBUG 0
            main()
            {
                #if DEBUG
                    printf("Debugging\n");
                #endif
                    printf("Running\n");
            }
        由於程序定義DEBUG宏代表0,所以#if條件爲假,不編譯後面的代碼直到#endif,所以程序直接輸出Running。
        如果去掉#define語句,效果是一樣的。
    3.#ifdef和#ifndef
        #define DEBUG
        main()
        {
            #ifdef DEBUG
                printf("yes\n");
            #endif
            #ifndef DEBUG
                printf("no\n");
            #endif
        }
        #if defined等價於#ifdef; #if !defined等價於#ifndef
    4.#else指令
        #else指令用於某個#if指令之後,當前面的#if指令的條件不爲真時,就編譯#else後面的代碼。#endif指令將中指上面的條件塊。
        #define DEBUG
        main()
        {
            #ifdef DEBUG
                printf("Debugging\n");
            #else
                printf("Not debugging\n");
            #endif
                printf("Running\n");
       }
    5.#elif指令
        #elif預處理指令綜合了#else和#if指令的作用。
        #define TWO
        main()
        {
            #ifdef ONE
                printf("1\n");
            #elif defined TWO
                printf("2\n");
            #else
                printf("3\n");
            #endif
        }
        程序很好理解,最後輸出結果是2。
    6.其他一些標準指令
        #error指令將使編譯器顯示一條錯誤信息,然後停止編譯。
        #line指令可以改變編譯器用來指出警告和錯誤信息的文件號和行號。
        #pragma指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告信息。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章