作者:zyl910
在编写跨平台的程序时,我们经常使用预定义宏来检测编译环境。虽然编译器的手册中有预处理宏的介绍,但是不够详细,而且还有很多宏没有介绍。于是,我编写了一个小程序,显示常见C/C++编译器的编译器的预定义宏。
一、心得
最直接的办法是逐个逐个的用#ifdef判断宏是否存在,然后再printf显示其内容。可是预定义宏有些是整数、有些是字符串,还有些是关键字不能直接用printf输出,用起来挺麻烦的。
在网上发现一种不错办法,出自《关于CPP的预定义宏:unix、linux、i386、i586,大家中过招吗?》4楼“太平绅士”——
点击(此处)折叠或打开
- #include <stdio.h>
- #define PT_MAKE_STR(x) { #x, PT_MAKE_STR_ESC(x) }
- #define PT_MAKE_STR_ESC(x) #x
- typedef struct
- {
- const char *name;
- const char *value;
- } MACRO_T;
- /* Compilers */
- const MACRO_T g_compilers[ ] =
- {
- #ifdef __INTEL_COMPILER /* Interl C++ */
- PT_MAKE_STR( __INTEL_COMPILER ),
- #endif
-
- #ifdef _MSC_VER /* Visual C++ */
- PT_MAKE_STR( _MSC_VER ),
- #endif
-
- #ifdef __GNUC__ /* GCC */
- PT_MAKE_STR( __GNUC__ ),
- #endif
-
- #ifdef __DMC__ /* DMC++ */
- PT_MAKE_STR( __DMC__ ),
- #endif
-
- #ifdef __ARMCC_VERSION /* ARM C/C++ */
- PT_MAKE_STR( __ARMCC_VERSION ),
- #endif
- };
- /* Operation system */
- const MACRO_T g_platforms[ ] =
- {
- #ifdef _WIN32 /* Windows 32 or Windows 64 */
- PT_MAKE_STR( _WIN32 ),
- #endif
-
- #ifdef _WIN64 /* Windows 64 */
- PT_MAKE_STR( _WIN64 ),
- #endif
-
- #ifdef __MINGW32__ /* Windows32 by mingw compiler */
- PT_MAKE_STR( __MINGW32__ ),
- #endif
-
- #ifdef __CYGWIN__ /* Cygwin */
- PT_MAKE_STR( __CYGWIN__ ),
- #endif
-
- #ifdef __linux__ /* linux */
- PT_MAKE_STR( __linux__ ),
- #endif
-
- #ifdef __FreeBSD__ /* FreeBSD */
- PT_MAKE_STR( __FreeBSD__ ),
- #endif
-
- #ifdef __NetBSD__ /* NetBSD */
- PT_MAKE_STR( __NetBSD__ ),
- #endif
-
- #ifdef __OpenBSD__ /* OpenBSD */
- PT_MAKE_STR( __OpenBSD__ ),
- #endif
-
- #ifdef __sun__ /* Sun OS */
- PT_MAKE_STR( __sun__ ),
- #endif
-
- #ifdef __MaxOSX__ /* MAC OS X */
- PT_MAKE_STR( __MaxOSX__ ),
- #endif
-
- #ifdef __unix__ /* unix */
- PT_MAKE_STR( __unix__ ),
- #endif
- };
- /* Other useful */
- const MACRO_T g_others[ ] =
- {
- #ifdef __DATE__
- PT_MAKE_STR( __DATE__ ),
- #endif
-
- #ifdef __TIME__
- PT_MAKE_STR( __TIME__ ),
- #endif
-
- #ifdef _BSD_SOURCE
- PT_MAKE_STR( _BSD_SOURCE ),
- #endif
-
- #ifdef _POSIX_SOURCE
- PT_MAKE_STR( _POSIX_SOURCE ),
- #endif
-
- #ifdef _XOPEN_SOURCE
- PT_MAKE_STR( _XOPEN_SOURCE ),
- #endif
-
- #ifdef _GNU_SOURCE
- PT_MAKE_STR( _GNU_SOURCE ),
- #endif
-
- #ifdef __GNUC_MINOR__
- PT_MAKE_STR( __GNUC_MINOR__ ),
- #endif
-
- #ifdef __VERSION__
- PT_MAKE_STR( __VERSION__ ),
- #endif
-
- #ifdef __unix
- PT_MAKE_STR( __unix ),
- #endif
- };
- int main( int argc, char **argv )
- {
- int i;
-
- printf( "/* Compiler definitions. */\n" );
- for( i = 0; i < sizeof( g_compilers ) / sizeof( g_compilers[ 0 ] ); ++i )
- {
- printf( "#define %s %s\n", g_compilers[ i ].name, g_compilers[ i ].value );
- }
- printf( "\n" );
-
- printf( "/* Platform definitions. */\n" );
- for( i = 0; i < sizeof( g_platforms ) / sizeof( g_platforms[ 0 ] ); ++i )
- {
- printf( "#define %s %s\n", g_platforms[ i ].name, g_platforms[ i ].value );
- }
- printf( "\n" );
-
- printf( "/* Other definitions. */\n" );
- for( i = 0; i < sizeof( g_others ) / sizeof( g_others[ 0 ] ); ++i )
- {
- printf( "#define %s %s\n", g_others[ i ].name, g_others[ i ].value );
- }
- printf( "\n" );
-
- return 0;
- }
该方法巧妙的利用“#”运算将宏转成了字符串并填写数组,然后程序只需显示数组内容就行了。
我在该方法的基础上做了三点改进——
1. main函数中有很多相似的代码,区别仅仅是数组的不同。可以编写一个print_MACRO_T函数来显示MACRO_T数组,然后在main函数中对每一个数组调用该函数。
2. 当某个数组的宏均不存在时,编译器会报错。可以在数组的第一行填上该类别的描述信息,保证编译通过。另一个好处是精简了main函数中显示不同类别描述信息的代码。
3. 某些编译器不支持内容为空的宏(如BCB6)。这时只有手动#if做兼容性处理了。
二、全部代码
预定义宏的数据来自——C11标准、C++11标准,及VC、BCB、Intel、GCC这些编译器。
最初想删除重名的宏,后来考虑到需要对照各个编译器的手册,所以还是允许重名比较好。
全部代码——
点击(此处)折叠或打开
- #include <stdio.h>
- #define PT_MAKE_STR(x) { #x, PT_MAKE_STR_ESC(x) }
- #define PT_MAKE_STR_ESC(x) #x
- typedef struct tagMACRO_T
- {
- const char *name;
- const char *value;
- } MACRO_T;
- /* Compilers */
- const MACRO_T g_compilers[] =
- {
- {"[Compiler]", ""},
-
- #ifdef _MSC_VER /* Visual C++ */
- PT_MAKE_STR( _MSC_VER ),
- #endif
-
- #ifdef __BORLANDC__
- PT_MAKE_STR(__BORLANDC__),
- #endif
-
- #ifdef __INTEL_COMPILER /* Interl C++ */
- PT_MAKE_STR( __INTEL_COMPILER ),
- #endif
-
- #ifdef __GNUC__ /* GCC */
- PT_MAKE_STR( __GNUC__ ),
- #endif
-
- #ifdef __DMC__ /* DMC++ */
- PT_MAKE_STR( __DMC__ ),
- #endif
-
- #ifdef __ARMCC_VERSION /* ARM C/C++ */
- PT_MAKE_STR( __ARMCC_VERSION ),
- #endif
-
- #ifdef __APPLE_CC__ /* Apple's own GCC */
- PT_MAKE_STR( __APPLE_CC__ ),
- #endif
- };
- /* Operation system */
- const MACRO_T g_platforms[] =
- {
- {"[Platform]", ""},
-
- #ifdef __i386__
- PT_MAKE_STR(__i386__),
- #endif
-
- #ifdef __x86_64__
- PT_MAKE_STR(__x86_64__),
- #endif
-
- #ifdef __AMD64__
- PT_MAKE_STR(__AMD64__),
- #endif
-
- #ifdef __amd64__
- PT_MAKE_STR(__amd64__),
- #endif
-
- #ifdef __ia64__
- PT_MAKE_STR(__ia64__),
- #endif
-
- #ifdef __alpha__
- PT_MAKE_STR(__alpha__),
- #endif
-
- #ifdef __arm__
- PT_MAKE_STR(__arm__),
- #endif
-
- #ifdef __sparc__
- PT_MAKE_STR(__sparc__),
- #endif
-
- #ifdef __arch64__
- PT_MAKE_STR(__arch64__),
- #endif
-
- #ifdef __powerpc__
- PT_MAKE_STR(__powerpc__),
- #endif
-
- #ifdef __powerpc64__
- PT_MAKE_STR(__powerpc64__),
- #endif
-
- #ifdef __ppc__
- PT_MAKE_STR(__ppc__),
- #endif
-
- #ifdef __ppc64__
- PT_MAKE_STR(__ppc64__),
- #endif
-
- #ifdef _WIN32 /* Windows 32 or Windows 64 */
- PT_MAKE_STR( _WIN32 ),
- #endif
-
- #ifdef _WIN64 /* Windows 64 */
- PT_MAKE_STR( _WIN64 ),
- #endif
-
- #ifdef __MINGW32__ /* Windows32 by mingw compiler */
- PT_MAKE_STR( __MINGW32__ ),
- #endif
-
- #ifdef __CYGWIN__ /* Cygwin */
- PT_MAKE_STR( __CYGWIN__ ),
- #endif
-
- #ifdef __linux__ /* linux */
- PT_MAKE_STR( __linux__ ),
- #endif
-
- #ifdef __FreeBSD__ /* FreeBSD */
- PT_MAKE_STR( __FreeBSD__ ),
- #endif
-
- #ifdef __NetBSD__ /* NetBSD */
- PT_MAKE_STR( __NetBSD__ ),
- #endif
-
- #ifdef __OpenBSD__ /* OpenBSD */
- PT_MAKE_STR( __OpenBSD__ ),
- #endif
-
- #ifdef __sun__ /* Sun OS */
- PT_MAKE_STR( __sun__ ),
- #endif
-
- #ifdef __MaxOSX__ /* MAC OS X */
- PT_MAKE_STR( __MaxOSX__ ),
- #endif
-
- #ifdef __unix__ /* unix */
- PT_MAKE_STR( __unix__ ),
- #endif
-
- ////////////////////////////////////////
- #ifdef __APPLE__
- PT_MAKE_STR( __APPLE__ ),
- #endif
-
- #ifdef linux
- PT_MAKE_STR( linux ),
- #endif
-
- #ifdef _LINUX
- PT_MAKE_STR( _LINUX ),
- #endif
-
- #ifdef __USE_BSD
- PT_MAKE_STR( __USE_BSD ),
- #endif
-
- };
- /* Standard C. C11, C++11 */
- const MACRO_T g_stdc[] =
- {
- /* [C11]: ISO/IEC 9899:2011 - Information technology -- Programming languages -- C. http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=57853 */
- /* [C++11]: ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++. http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372 */
- {"[Standard C]", ""},
-
- /* [C11] 6.10.8.1 Mandatory macros */
- #ifdef __FILE__
- PT_MAKE_STR(__FILE__),
- #endif
-
- #ifdef __LINE__
- PT_MAKE_STR(__LINE__),
- #endif
-
- #ifdef __DATE__
- PT_MAKE_STR(__DATE__),
- #endif
-
- #ifdef __TIME__
- PT_MAKE_STR(__TIME__),
- #endif
-
- #ifdef __TIMESTAMP__
- PT_MAKE_STR(__TIMESTAMP__),
- #endif
-
- #ifdef __STDC__
- PT_MAKE_STR(__STDC__),
- #endif
-
- #ifdef __STDC_HOSTED__
- PT_MAKE_STR(__STDC_HOSTED__),
- #endif
-
- #ifdef __STDC_VERSION__
- PT_MAKE_STR(__STDC_VERSION__),
- #endif
-
- /* [C11] 6.10.8.2 Environment macros */
- #ifdef __STDC_ISO_10646__
- PT_MAKE_STR(__STDC_ISO_10646__),
- #endif
-
- #ifdef __STDC_MB_MIGHT_NEQ_WC__
- PT_MAKE_STR(__STDC_MB_MIGHT_NEQ_WC__),
- #endif
-
- #ifdef __STDC_UTF_16__
- PT_MAKE_STR(__STDC_UTF_16__),
- #endif
-
- #ifdef __STDC_UTF_32__
- PT_MAKE_STR(__STDC_UTF_32__),
- #endif
-
- /* [C11] 6.10.8.3 Conditional feature macros */
- #ifdef __STDC_ANALYZABLE__
- PT_MAKE_STR(__STDC_ANALYZABLE__),
- #endif
-
- #ifdef __STDC_IEC_559__
- PT_MAKE_STR(__STDC_IEC_559__),
- #endif
-
- #ifdef __STDC_IEC_559_COMPLEX__
- PT_MAKE_STR(__STDC_IEC_559_COMPLEX__),
- #endif
-
- #ifdef __STDC_LIB_EXT1__
- PT_MAKE_STR(__STDC_LIB_EXT1__),
- #endif
-
- #ifdef __STDC_NO_ATOMICS__
- PT_MAKE_STR(__STDC_NO_ATOMICS__),
- #endif
-
- #ifdef __STDC_NO_COMPLEX__
- PT_MAKE_STR(__STDC_NO_COMPLEX__),
- #endif
-
- #ifdef __STDC_NO_THREADS__
- PT_MAKE_STR(__STDC_NO_THREADS__),
- #endif
-
- #ifdef __STDC_NO_VLA__
- PT_MAKE_STR(__STDC_NO_VLA__),
- #endif
-
- /* [C++11] 16.8 Predefined macro names */
- #ifdef __cplusplus
- PT_MAKE_STR(__cplusplus),
- #endif
-
- #ifdef __STDCPP_STRICT_POINTER_SAFETY__
- PT_MAKE_STR(__STDCPP_STRICT_POINTER_SAFETY__),
- #endif
-
- #ifdef __STDCPP_THREADS__
- PT_MAKE_STR(__STDCPP_THREADS__),
- #endif
-
- ////////////////////////////////////////
- #ifdef __OBJC__
- PT_MAKE_STR(__OBJC__),
- #endif
-
- #ifdef __ASSEMBLER__
- PT_MAKE_STR(__ASSEMBLER__),
- #endif
-
- #ifdef NDEBUG
- PT_MAKE_STR(NDEBUG),
- #endif
- };
- /* Microsoft Visual C++. VC++ 2012 */
- const MACRO_T g_vc[] =
- {
- {"[Visual C++]", ""},
-
- #ifdef _ATL_VER
- PT_MAKE_STR(_ATL_VER),
- #endif
-
- #ifdef _CHAR_UNSIGNED
- PT_MAKE_STR(_CHAR_UNSIGNED),
- #endif
-
- #ifdef __CLR_VER
- PT_MAKE_STR(__CLR_VER),
- #endif
-
- #ifdef __cplusplus_cli
- PT_MAKE_STR(__cplusplus_cli),
- #endif
-
- #ifdef __COUNTER__
- PT_MAKE_STR(__COUNTER__),
- #endif
-
- #ifdef __cplusplus
- PT_MAKE_STR(__cplusplus),
- #endif
-
- #ifdef _CPPRTTI
- PT_MAKE_STR(_CPPRTTI),
- #endif
-
- #ifdef _CPPUNWIND
- PT_MAKE_STR(_CPPUNWIND),
- #endif
-
- #ifdef _DEBUG
- #if (defined(__BORLANDC__))
- {"_DEBUG", "#"},
- #else
- PT_MAKE_STR(_DEBUG),
- #endif
- #endif
-
- #ifdef _DLL
- PT_MAKE_STR(_DLL),
- #endif
-
- #ifdef __FUNCDNAME__
- PT_MAKE_STR(__FUNCDNAME__),
- #endif
-
- #ifdef __FUNCSIG__
- PT_MAKE_STR(__FUNCSIG__),
- #endif
-
- #ifdef __FUNCTION__
- PT_MAKE_STR
点击(此处)折叠或打开
简单应用:
参考文献——
《ISO/IEC 9899:2011 - Information technology -- Programming languages -- C》. ISO/IEC, 2011.http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=57853
《ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++》. ISO/IEC, 2011.http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372
《[VS2012] Predefined Macros》. Microsoft, 2012. http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.110).aspx
《[VS2012] 预定义的宏》. Microsoft, 2012. http://msdn.microsoft.com/zh-cn/library/b0084kay(v=vs.110).aspx
《[BCB6] C++Builder Language Guide》中的《Predefined macros》. Borland, 2002.
《Intel? C++ Compiler XE 12.1 User and Reference Guides》(Windows版)中的《Additional Predefined Macros》. Intel, 2011.http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/2011Update/cpp/win/index.htm
《Intel? C++ Compiler XE 12.1 User and Reference Guides》(Linux版)中的《Additional Predefined Macros》. Intel, 2011.http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/2011Update/cpp/lin/index.htm
《[GCC] The C Preprocessor》中的《3.7.2 Common Predefined Macros》. GNU, 2011. http://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
《关于CPP的预定义宏:unix、linux、i386、i586,大家中过招吗?》. 太平绅士, 2009-02-10. http://bbs.chinaunix.net/thread-1366571-1-1.html
《C\C++宏大全》. http://www.cnblogs.com/sevencat/archive/2004/06/10/14872.html
《Useful GCC Macros》. OneSadCookie, 2007-07-12. http://blog.onesadcookie.com/2007/07/useful-gcc-macros.html
《[笔记] Intel C++编译器的预定义宏(Windows版、Linux版)》. http://www.cnblogs.com/zyl910/archive/2012/07/06/intel_predefined_macros.html