ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别
- ANSI C and Microsoft C++中常用的預(yù)定義宏以及 宏定義中 # 和 ## 的區(qū)別
- 第一部分,常見的預(yù)定義宏
- 第二部分,# 和 ## 再宏定義中的使用說明
- 第三部分,類似 #pragma push_macro(“new”) 的使用說明
ANSI C and Microsoft C++中常用的預(yù)定義宏以及 宏定義中 # 和 ## 的區(qū)別
第一部分,常見的預(yù)定義宏
__FILE__ 源文件的名稱 如XXX.cpp __LINE__ 代碼在源文件中是第幾行 __DATE__ 源文件完成日期如Aug 17 2011 __TIME__ 源文件完成時(shí)間如19:31:13 __TIMESTAMP__ 源文件完成日期時(shí)間如Wed Aug 17 19:27:36 2011如分配內(nèi)存函數(shù)malloc()的一個(gè)版本就使用了上面的宏
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)另外可以在程序中使用__FILE__和__LINE__來確定是哪個(gè)文件哪一行出錯(cuò):
char *pszFileName = (char*)malloc(MAX_PATH * sizeof(char));if (pszFileName == NULL)printf("Error in %s %d\n", __FILE__, __LINE__);當(dāng)然實(shí)際程序中大多用__FILE__和__LINE__快速定位錯(cuò)誤后不會(huì)直接輸出,而是通過另一程序來將這些信息以EMAIL形式反饋給開發(fā)人員。
對__FILE__可以方便的轉(zhuǎn)化成wchar_t類型,MSDN就有這個(gè)例子:
#define WIDEN2(x) L ## x#define WIDEN(x) WIDEN2(x)#define __WFILE__ WIDEN(__FILE__)wchar_t *pwsz = __WFILE__;第二部分,# 和 ## 再宏定義中的使用說明
文中__FILE__與示例1的可以參見《使用ANSI C and Microsoft C++中常用的預(yù)定義宏》
宏中的#的功能是將其后面的宏參數(shù)進(jìn)行字符串化操作(Stringizing operator),簡單說就是在它引用的宏變量的左右各加上一個(gè)雙引號。
如定義好#define STRING(x) #x之后,下面二條語句就等價(jià)。
char *pChar = "hello";char *pChar = STRING(hello);還有一個(gè)#@是加單引號(Charizing Operator)
#define makechar(x) #@xchar ch = makechar(b);與char ch = 'b';等價(jià)。但有小問題要注意,宏中遇到#或##時(shí)就不會(huì)再展開宏中嵌套的宏了。什么意思了?比如使用char *pChar = STRING(__FILE__);雖然__FILE__本身也是一個(gè)宏,但編譯器不會(huì)展開它,所以pChar將指向"__FILE__"而不是你要想的形如”D:\XXX.cpp”的源文件名稱。因此要加一個(gè)中間轉(zhuǎn)換宏,先將__FILE__解析成”D:\XXX.cpp”字符串。
定義如下所示二個(gè)宏:
#define _STRING(x) #x#define STRING(x) _STRING(x)再調(diào)用下面語句將輸出帶”“的源文件路徑
char* pChar = STRING(__FILE__);printf("%s %s\n", pChar, __FILE__);可以比較下STRING(__FILE__)與__FILE__的不同,前將帶雙引號,后一個(gè)沒有雙引號。
再講下##的功能,它可以拼接符號(Token-pasting operator)。
MSDN上有個(gè)例子:
#define paster( n ) printf( "token"#n" = %d\n", token##n )int token9 = 100;
再調(diào)用 paster(9);宏展開后token##n直接合并變成了token9。整個(gè)語句變成了
printf( “token”“9”” = %d”, token9 );
在C語言中字符串中的二個(gè)相連的雙引號會(huì)被自動(dòng)忽略,于是上句等同于
printf(“token9 = %d”, token9);。
即輸出token9 = 100
有了上面的基礎(chǔ)后再來看示例1
#define WIDEN2(x) L ## x#define WIDEN(x) WIDEN2(x)#define __WFILE__ WIDEN(__FILE__)wchar_t *pwsz = __WFILE__;第一個(gè)宏中的L是將ANSI字符串轉(zhuǎn)化成unicode字符串。如:wchar_t *pStr = L”hello”;
再來看wchar_t *pwsz = __WFILE__;
__WFILE__被首先展開成WIDEN(__FILE__),再展開成WIDEN2("__FILE__表示的字符串"),再拼接成 L"__FILE__表示的字符串” 即L”D:\XXX.cpp” 從而得到unicode字符串并取字符串地址賦值給pwsz指針。
在VC中_T(),TEXT ()也是用的這種技術(shù)。
在tchar.h頭文件中可以找到:
#define _T(x) __T(x)#define __T(x) L ## x在winnt.h頭文件中可以找到
#define TEXT(quote) __TEXT(quote) // r_winnt#define __TEXT(quote) L##quote // r_winnt因此不難理解為什么第三條語句會(huì)出錯(cuò)error C2065: ‘LszText’ : undeclared identifier
wprintf(TEXT("%s %s\n"), _T("hello"), TEXT("hello"));char szText[] = "hello";wprintf(TEXT("%s %s\n"), _T(szText), TEXT(szText));而將”hello”定義成宏后就能正確運(yùn)行。
#define SZTEXT "hello"wprintf(TEXT("%s %s\n"), _T(SZTEXT), TEXT(SZTEXT));注:由于VC6.0默認(rèn)是ANSI編碼,因此要先設(shè)置成unicode編碼,在project菜單中選擇Setting,再在C/C++標(biāo)簽對話框中的Category中選擇Preprocessor。再地Preprocessor definitions編輯框中將_MBCS去掉,加上_UNICODE,UNICODE。
更多內(nèi)容可以查考MSDN上對Preprocessor Operators的講解。
第三部分,類似 #pragma push_macro(“new”) 的使用說明
在三方庫源碼中,我們經(jīng)常看到這樣的代碼:
#pragma push_macro("new")#undef new// do something with new......#pragma pop_macro("new")它的作用就是將宏定義new壓入棧并取消它(指的是宏)的定義,如此一來,new的本來含義便獲得了恢復(fù),使用完畢后將宏定義new彈出棧,恢復(fù)宏定義。
不過,仍有下面兩個(gè)問題需要回答。
1)宏定義名不會(huì)與關(guān)鍵字new沖突嗎?
2)宏定義new有何作用?
問題1
宏定義名若與保留的關(guān)鍵字相同,編譯器并不會(huì)提示錯(cuò)誤,而是用最新定義的宏定義代替關(guān)鍵字發(fā)揮作用。下面是一個(gè)例子,定義了宏int。例程能順利通過編譯鏈接,其運(yùn)行結(jié)果為8,4,8,與預(yù)期相同。
// ConsoleTest.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。 //#include "stdafx.h" #include <iostream> using namespace std; #define int doublevoid _tmain(int argc, _TCHAR* argv[]) {int iOne = 1;cout<<sizeof(iOne)<<endl;#pragma push_macro("int")#undef intint iTwo = 2;cout<<sizeof(iTwo)<<endl;#pragma pop_macro("int")int iSecond=2;cout<<sizeof(iSecond)<<endl;system("pause"); }解析:運(yùn)行結(jié)果為8 ,4,8
宏定義,如#define PI 3.1415926 把程序中出現(xiàn)的PI全部換成3.1415926
#define int double 該句話表明,把程序中出現(xiàn)int的地方全部替換為double , (int iOne = 1;cout<<sizeof(iOne)<<endl;相當(dāng)于iOne為double類型,所以輸出8) #pragma push_macro("int")#undef intint iTwo = 2;cout<<sizeof(iTwo)<<endl;#pragma pop_macro("int")上面幾句的意思是,將將宏定義int壓入棧并取消它(指的是宏)的定義,如此一來,int的本來含義便獲得了恢復(fù),即int仍代表int。使用完畢后將宏定義int彈出棧,恢復(fù)宏定義即int代表double。
轉(zhuǎn)載自:
1、https://blog.csdn.net/MoreWindows/article/details/6697488
2、https://blog.csdn.net/ivan_ljf/article/details/8787189
感謝優(yōu)秀博主的分享。
總結(jié)
以上是生活随笔為你收集整理的ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ServletContext(重要)
- 下一篇: 想要涨薪,这些坑你避开了