_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

GNUCGNUC_MINORGNUC_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

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

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進行編寫代碼,至於其他預定義的宏呢可以去本文剛開始的時候給出的網站上查看,他們各自的作用也都寫的非常清楚。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章