1 __GNUC__ / __GNUG__是gcc / g++編譯器編譯代碼時預約義的一個宏。須要針對gcc / g++編寫代碼時, 能夠使用該宏進行條件編譯。ios
2 __GNUC__ / __GNUG__的值表示gcc / g++的版本。須要針對gcc / g++特定版本編寫代碼時,也能夠使用該宏進行條件編譯。windows
3 __GNUC__ / __GNUG__的類型是「int」,該宏被擴展後, 獲得的是整數字面值。能夠經過僅預處理,查看宏擴展後的文本。函數
#include <assert.h> #include <stdio.h> #include <typeinfo> #ifndef __GNUC__ /* error sample for gcc compiler */ #elif __GNUG__ /* error sample for gcc compiler */ #else /* use gcc special extension: #warning , __attribute__, etc. */ #endif int main() { printf("hello gcc %d\n",__GNUC__); assert( typeid(__GNUC__)==typeid(int) ); printf("press Enter to exit\n"); (void)getchar(); return 0; }
1 _MSC_VER是微軟C/C++編譯器——cl.exe編譯代碼時預約義的一個宏。須要針對cl編寫代碼時, 能夠使用該宏進行條件編譯。spa
2 _MSC_VER的值表示cl的版本。須要針對cl特定版本編寫代碼時, 也能夠使用該宏進行條件編譯。翻譯
3 _MSC_VER的類型是"int"。該宏被擴展後,獲得的是整數字面值。能夠經過僅預處理, 查看宏擴展後的文本。code
/* _MSC_VER\_MSC_VER.cpp */ #include <stdio.h> #include <stdlib.h> #include <typeinfo> #define TO_LITERAL(text) TO_LITERAL_(text) #define TO_LITERAL_(text) #text #ifndef _MSC_VER #error sample for msvc compiler #else /* use msvc special extension: #pragma message,__declspec,__stdcall,etc. */ #pragma message("----------------------------------------\n") #pragma message("----------------------------------------\n") #pragma message("---------- hello msvc " TO_LITERAL(_MSC_VER) " -------------") #pragma message("\n----------------------------------------\n") #pragma message("----------------------------------------\n") extern __declspec(dllimport) void __stdcall declare_but_dont_reference(void); #endif int main() { printf("hello msvc, version=%d\n",_MSC_VER); printf("typeof _MSC_VER=\"%s\"\n",typeid(_MSC_VER).name()); system("pause"); /* msvc only on windows? */ return 0; }
__FILE__:當前程序行所在源文件名稱,標準C支持,該宏當作字符串對待;
__LINE__:當前程序行所在源文件內的行號,標準C支持,該宏當作整形對待;
__FUNCTION__(或__func__):當前程序行所屬的函數名稱,C99支持(如:VC++6.0不支持),該宏當作字符串對待;ci
#include <iostream> using namespace std; int main(int argc, char *argv[]) { printf("[%s:%d]%s|%s\n", __FILE__, __LINE__, __FUNCTION__, __func__); return 0; }
執行上述程序將打印: 字符串
[test.cpp:8]main|main
__DATE__:當前文件的編譯日期,格式是Mmm:dd:yyyy。該宏當作字符串對待。
__TIME__:當前文件的編譯時間,格式是hh:mm:ss。該宏當作字符串對待。get
#include <iostream> using namespace std; int main(int argc, char *argv[]) { printf("DATE:%s|TIME:%s\n", __DATE__, __TIME__); getchar(); return 0; }
執行上述程序將打印:編譯器
DATE:Oct 20 2010|TIME:23:33:24
1 "#":替換宏參數時,將其後面的宏參數轉換成帶引號的字符串,例如:
#define STR(s) #s int main( ) { std::string str = STR(abcdefg); return 0; }
C編譯器在預處理代碼時,第5行實際翻譯成:std::string str = "abcdefg";
2 "##":將該符號先後的兩個宏參數鏈接在一塊兒,好比:
#define PRINT(PRINT_FUNNAME, VAR) print_##PRINT_FUNNAME(VAR) int main() { PRINT(common, 5); return 0; }
C編譯器在預處理代碼時,第5行實際翻譯成:print_common(5);
咱們實際看下綜合運用的例子:
#include <iostream> using namespace std; #define PRINT(fun, name, var) print_##fun(#name, var) void print_common(const std::string & name, int var) { std::cout << name.c_str() << ":" << var << std::endl; } void print_tofile(const std::string & name, int var) { char sz_temp[1024]; memset(sz_temp, 0, sizeof(sz_temp)); snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var); FILE * fp = fopen("./log.log", "w"); fwrite(sz_temp, 1, strlen(sz_temp), fp); fclose(fp); } int main() { PRINT(common, age, 5); PRINT(tofile, age, 5); return 0; }