gcc中預定義的宏__GNUC__


今天在看Linux系統編程這本書的代碼的時候看到了__GNUC__,不太清楚這個宏所以去查了一下,以此記錄。GNU C預定義了一系列的宏,這些宏都是以雙下划線開始的,這里只講一下__GNUC__  __GNUC_MINOR__ __GNUC_PATCHLEVEL__,其他GNU C的預定義宏可以到這里查看:

https://gcc.gnu.org/onlinedocs/gcc-5.1.0/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros

 

__GNUC__ 、__GNUC_MINOR__ 、__GNUC_PATCHLEVEL__分別代表gcc的主版本號,次版本號,修正版本號。這里引用一下上面的官方說明:

__GNUC__

__GNUC_MINOR__

__GNUC_PATCHLEVEL__

These macros are defined by all GNU compilers that use the C preprocessor: C, C++, Objective-C and Fortran. Their values are the major version, minor version, and patch level of the compiler, as integer constants. For example, GCC 3.2.1 will define __GNUC__ to 3, __GNUC_MINOR__ to 2, and __GNUC_PATCHLEVEL__ to 1. These macros are also defined if you invoke the preprocessor directly.

__GNUC_PATCHLEVEL__ is new to GCC 3.0; it is also present in the widely-used development snapshots leading up to 3.0 (which identify themselves as GCC 2.96 or 2.97, depending on which snapshot you have).

If all you need to know is whether or not your program is being compiled by GCC, or a non-GCC compiler that claims to accept the GNU C dialects, you can simply test __GNUC__. If you need to write code which depends on a specific version, you must be more careful. Each time the minor version is increased, the patch level is reset to zero; each time the major version is increased (which happens rarely), the minor version and patch level are reset. If you wish to use the predefined macros directly in the conditional, you will need to write it like this:

          /* Test for GCC > 3.2.0 */
          #if __GNUC__ > 3 || \
              (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
                                 (__GNUC_MINOR__ == 2 && \
                                  __GNUC_PATCHLEVEL__ > 0))

Another approach is to use the predefined macros to calculate a single number, then compare that against a threshold:

          #define GCC_VERSION (__GNUC__ * 10000 \
                               + __GNUC_MINOR__ * 100 \
                               + __GNUC_PATCHLEVEL__)
          ...
          /* Test for GCC > 3.2.0 */
          #if GCC_VERSION > 30200

Many people find this form easier to understand. 

 

上面這一大段英語實際是在講:

注意,__GNUC_PATCHLEVEL__是從gcc 3.0以后才有的,在這之前的gcc是沒有預定義這個宏的。我們可以用gcc --version來查看自己系統中的gcc版本,現在的gcc版本普遍都是3.0以后了吧,就我的系統而言,是4.9.2,那么對應的__GNUC__就是4,__GNUC_MINOR__就是9,__GNUC_PATCHLEVEL__就是2。這幾個宏的類型都是int,被擴展后,會得到整數的字面值。由於是宏,因此我們可以通過只預處理源程序來觀察他們的文本值。比如,只對下面這段代碼進行預處理,預處理(gcc -E)以后是對宏進行直接的替換,所以我們就能看到這三個宏的文本值:

#include <stdio.h>

int main()
{
#ifdef __GNUC__
    printf("__GNUC__ = %d\n",__GNUC__); 
#endif
#ifdef __GNUC_MINOR__
    printf("__GNUC_MINOR__ = %d\n",__GNUC_MINOR__); 
#endif
#ifdef __GNUC_PATCHLEVEL__
    printf("__GNUC_PATCHLEVEL__ = %d\n",__GNUC_PATCHLEVEL__);
#endif
    
    return 0;
}

 

預編譯以后的文件函數部分:

# 942 "/usr/include/stdio.h" 3 4

# 2 "test.c" 2

int main()
{

    printf("__GNUC__ = %d\n",4);


    printf("__GNUC_MINOR__ = %d\n",9);


    printf("__GNUC_PATCHLEVEL__ = %d\n",2);


    return 0;
}


這樣就很直觀地看到,__GNUC__被替換成了4,__GNUC_MINOR__被替換成了9,__GNUC_PATCHLEVEL__替換成了2。

為什么要預定義了這三個宏呢?這是為了方便我們在針對特定版本的gcc編譯器進行代碼編寫的,比如我們的代碼要求gcc的版本至少在3.2.0以上,我們就可以寫成如下方式的條件編譯:

/* Test for GCC > 3.2.0 */
#if __GNUC__ > 3 || \
  (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
    (__GNUC_MINOR__ == 2 && \
      __GNUC_PATCHLEVEL__ > 0)))
  printf("gcc > 3.2.0\n");
  //...
#endif

注意上面把條件編譯#if的條件寫成了多行的時候(和宏定義一樣,如果宏定義一行寫不完,要在最后加一個行繼續符'\'),每行最后的行繼續符'\'后面不能跟任何符號,空格、制表符等都不行,他表示下一行的也是並列條件(通常為||或&&的右操作數),通常在編譯以前會把行繼續符'\'以及前面的換行符都去掉,這樣就可以看作是同一行的了。

當然有的人覺得上面的條件那么大一串看起來非常不順眼,理解起來也不容易,這時候我們可以自己定義一個宏GCC_VERSION用來表示gcc版本,原理也很簡單就是把主版本號*10000+次版本號*100+修訂版本號,最終用這個值來判斷gcc的版本號:

#include <stdio.h>
#define GCC_VERSION (__GNUC__ * 10000 \
                   + __GNUC_MINOR__ * 100 \
                   + __GNUC_PATCHLEVEL__)
int main()
{
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200
    printf("gcc > 3.2.0\n");
    //...
#endif
    return 0;
}

 

好啦,對__GNUC__這個預定義的宏變量算是有了一個基本的了解,作用是用來針對特定版本的gcc進行編寫代碼,至於其他預定義的宏呢可以去本文剛開始的時候給出的網站上查看,他們各自的作用也都寫的非常清楚。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM