C語言中文網 目錄
首頁 > 編程筆記 > C語言筆記 閱讀:2,640

預定義宏,C語言預定義的宏詳解

對于預定義宏,相信大家并不陌生。為了方便處理一些有用的信息,預處理器定義了一些預處理標識符,也就是預定義宏。預定義宏的名稱都是以“__”(兩條下劃線)開頭和結尾的,如果宏名是由兩個單詞組成,那么中間以“_”(一條下劃線)進行連接。并且,宏名稱一般都由大寫字符組成。

在日常項目編程中,預定義宏尤其對多目標平臺代碼的編寫通常具有重大意義。通過預定義宏,程序員使用“#ifdef”與“#endif”等預處理指令,就可使平臺相關代碼只在適合于當前平臺的代碼上編譯,從而在同一套代碼中完成對多平臺的支持。從這個意義上講,平臺信息相關的宏越豐富,代碼的多平臺支持越準確。

標準 C 語言提供的一些標準預定義宏如表 1 所示。

表 1 常用的標準預定義宏
描 述
__DATE__ 丐前源文件的編澤口期,用 “Mmm dd yyy”形式的字符串常量表示
__FILE__ 當前源文件的名稱,用字符串常量表示
__LINE__ 當前源義件中的行號,用十進制整數常量表示,它可以隨#line指令改變
__TIME__ 當前源文件的最新編譯吋間,用“hh:mm:ss”形式的寧符串常量表示
__STDC__ 如果今前編澤器符合ISO標準,那么該宏的值為1,否則未定義
__STDC_VERSION__ 如果當前編譯器符合C89,那么它被定義為199409L;如果符合C99,那么它被定義為199901L:在其他情況下,該宏為宋定義
__STDC_HOSTED__ (C99)如果當前是宿主系統,則該宏的值為1;如果當前是獨立系統,則該宏的值為0
__STDC_IEC_559_ (C99)如果浮點數的實現符合IEC 60559標準時,則該宏的值為1,否則為未定義
__STDC_IEC_559_COMPLEX__ (C99)如果復數運算實現符合IEC60559標準時,則該宏的伉為1,否則為未定義
__STDC_ISO_10646__ (C99 )定義為長整型常量,yyyymmL表示wchai_t值遵循ISO 10646標準及其指定年月的修訂補充,否則該宏為未定義

除標準 C 語言提供的標準宏之外,各種編譯器也都提供了自己的自定義預定義宏。可以通過表 2 所示的指令來查看不同編譯器對預定義宏的支持情況。

表 2 不同編譯器的預定義宏查看指令
編譯器 宏指令(c) 宏指令(C++)
Clang/LLVM clang -dM -E -x c /dev/null clang++ -dM -E -x C++ /dev/null
GNU GCC/G++ gcc -dM -E -x c /dev/null g++ -dM -E -x C++ /dev/null
Hewlett-Packard C/aC++ cc -dM -E -x c /clev/null aCC -dM -E -x C++ /dev/null
IBM XL C/C++ xlc -qshowmacros -E /dev/null xlc++ -qshowmacros -E /dev/null
Intel ICC7ICPC icc -dM -E -x c /dev/null icpc -dM -E -x C++ /dev/null
Oracle Solaris Studio cc -xduinpmacros -E /dev/null CC -xduinpmacros -E /clev/null
Portland Group PGCC/PGCPP pgcc -dM -E  

圖 3 顯示了 GCC 編譯器預定義宏的查看結果。雖然各種編譯器的預定義宏不盡相同,但是一般都會支持“__DATE__、__FILE__、__LINE__與__TIME__”這 4 種預定義宏。


圖 3 查看 GCC 預定義宏

對于這些預定義宏的應用,基本上隨處可見,下面舉例介紹。

利用“__DATE__”和“__TIME__”宏可以用來確定程序編譯的時間。如下面的示例代碼所示:
int main (void)
{
    printf("Copyright (c) Powered by www.develhome.com\n");
    printf("Compiled on %s at %s\n", __DATE__,__TIME__);
    return 0;
}
利用“__STDC__”與“__STDC_VERSION__”宏可以編寫那些需要兼容標準 C 和非標準 C 編譯器的程序,如下面的示例代碼所示:
#ifdef __STDC__
/* Some version of standard C */
#if defined(__STDC__VERSION__)&&__STDC_VERSION__>=199901L
/* C99 */
#elif defined(__STDC_VERSION__)&&__STDC_VERSION__>=199409L
/* C89 and amendment 1 */
#else
/* C89 but not amendment 1*/
#endif
#else /* __STDC__not defined */
/*Not Standard C*/
#endif
利用__FILE__、__LINE__與__FUNCTION__(或者__func__)預定義宏的組合,在調試程序的時候可以很簡單地在程序運行期進行異常跟蹤。如下面的示例代碼所示:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define MESSAGE(message,assertion) \
          do{\
               if(!(assertion)){\
                    printf("line %d in %s(%s)", __LINE__, __FILE__,__FUNCTION__);\
                       if(message){\
                            printf(":%s",message);\
                          }\
                          printf("\n");\
                          abort();\
                 }\
             }while(0)
int OpenFile(const char *filename)
{
    int fd;
    MESSAGE("文件名稱不能夠為空",filename);
    MESSAGE("文件不存在",0==access(filename,F_OK));
    fd = open(filename,O_RDONLY);
    close(fd);
    return 0;
}
int main(int argc,char **argv)
{
    MESSAGE("命令參數不能夠為空",argc==2);
    OpenFile(argv[1]);
    return 0;
}
其中,__FILE__、__LINE__與__FUNCTION__(或者__func__)預定義宏分別表示文件名、行數與函數名,這樣就可以幫助我們精確地定位出現異常的文件、行數與函數名。運行結果如圖 4 所示。


圖 4

最后還需要注意的是,如果用戶重定義“#define“或取消了“#undef”預定義宏,那么其結果是“未定義”的。因此,在代碼編寫中,應該盡量避免自定義宏與預定義宏名稱相同的情況發生。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo