日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别

發布時間:2025/3/15 c/c++ 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • ANSI C and Microsoft C++中常用的預定義宏以及 宏定義中 # 和 ## 的區別
    • 第一部分,常見的預定義宏
    • 第二部分,# 和 ## 再宏定義中的使用說明
    • 第三部分,類似 #pragma push_macro(“new”) 的使用說明

ANSI C and Microsoft C++中常用的預定義宏以及 宏定義中 # 和 ## 的區別

第一部分,常見的預定義宏

__FILE__ 源文件的名稱 如XXX.cpp __LINE__ 代碼在源文件中是第幾行 __DATE__ 源文件完成日期如Aug 17 2011 __TIME__ 源文件完成時間如19:31:13 __TIMESTAMP__ 源文件完成日期時間如Wed Aug 17 19:27:36 2011

如分配內存函數malloc()的一個版本就使用了上面的宏

#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)

另外可以在程序中使用__FILE__和__LINE__來確定是哪個文件哪一行出錯:

char *pszFileName = (char*)malloc(MAX_PATH * sizeof(char));if (pszFileName == NULL)printf("Error in %s %d\n", __FILE__, __LINE__);

當然實際程序中大多用__FILE__和__LINE__快速定位錯誤后不會直接輸出,而是通過另一程序來將這些信息以EMAIL形式反饋給開發人員。

對__FILE__可以方便的轉化成wchar_t類型,MSDN就有這個例子:

#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++中常用的預定義宏》

宏中的#的功能是將其后面的宏參數進行字符串化操作(Stringizing operator),簡單說就是在它引用的宏變量的左右各加上一個雙引號。

如定義好#define STRING(x) #x之后,下面二條語句就等價。

char *pChar = "hello";char *pChar = STRING(hello);

還有一個#@是加單引號(Charizing Operator)

#define makechar(x) #@xchar ch = makechar(b);與char ch = 'b';等價。

但有小問題要注意,宏中遇到#或##時就不會再展開宏中嵌套的宏了。什么意思了?比如使用char *pChar = STRING(__FILE__);雖然__FILE__本身也是一個宏,但編譯器不會展開它,所以pChar將指向"__FILE__"而不是你要想的形如”D:\XXX.cpp”的源文件名稱。因此要加一個中間轉換宏,先將__FILE__解析成”D:\XXX.cpp”字符串。

定義如下所示二個宏:

#define _STRING(x) #x#define STRING(x) _STRING(x)

再調用下面語句將輸出帶”“的源文件路徑

char* pChar = STRING(__FILE__);printf("%s %s\n", pChar, __FILE__);

可以比較下STRING(__FILE__)與__FILE__的不同,前將帶雙引號,后一個沒有雙引號。

再講下##的功能,它可以拼接符號(Token-pasting operator)。

MSDN上有個例子:

#define paster( n ) printf( "token"#n" = %d\n", token##n )

int token9 = 100;

再調用 paster(9);宏展開后token##n直接合并變成了token9。整個語句變成了

printf( “token”“9”” = %d”, token9 );

在C語言中字符串中的二個相連的雙引號會被自動忽略,于是上句等同于

printf(“token9 = %d”, token9);。

即輸出token9 = 100

有了上面的基礎后再來看示例1

#define WIDEN2(x) L ## x#define WIDEN(x) WIDEN2(x)#define __WFILE__ WIDEN(__FILE__)wchar_t *pwsz = __WFILE__;

第一個宏中的L是將ANSI字符串轉化成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 ()也是用的這種技術。

在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

因此不難理解為什么第三條語句會出錯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”定義成宏后就能正確運行。

#define SZTEXT "hello"wprintf(TEXT("%s %s\n"), _T(SZTEXT), TEXT(SZTEXT));

注:由于VC6.0默認是ANSI編碼,因此要先設置成unicode編碼,在project菜單中選擇Setting,再在C/C++標簽對話框中的Category中選擇Preprocessor。再地Preprocessor definitions編輯框中將_MBCS去掉,加上_UNICODE,UNICODE。

更多內容可以查考MSDN上對Preprocessor Operators的講解。

第三部分,類似 #pragma push_macro(“new”) 的使用說明

在三方庫源碼中,我們經??吹竭@樣的代碼:

#pragma push_macro("new")#undef new// do something with new......#pragma pop_macro("new")

它的作用就是將宏定義new壓入棧并取消它(指的是宏)的定義,如此一來,new的本來含義便獲得了恢復,使用完畢后將宏定義new彈出棧,恢復宏定義。

不過,仍有下面兩個問題需要回答。

1)宏定義名不會與關鍵字new沖突嗎?

2)宏定義new有何作用?

問題1

宏定義名若與保留的關鍵字相同,編譯器并不會提示錯誤,而是用最新定義的宏定義代替關鍵字發揮作用。下面是一個例子,定義了宏int。例程能順利通過編譯鏈接,其運行結果為8,4,8,與預期相同。

// ConsoleTest.cpp : 定義控制臺應用程序的入口點。 //#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"); }

解析:運行結果為8 ,4,8

宏定義,如#define PI 3.1415926 把程序中出現的PI全部換成3.1415926

#define int double 該句話表明,把程序中出現int的地方全部替換為double , (int iOne = 1;cout<<sizeof(iOne)<<endl;相當于iOne為double類型,所以輸出8#pragma push_macro("int")#undef intint iTwo = 2;cout<<sizeof(iTwo)<<endl;#pragma pop_macro("int")

上面幾句的意思是,將將宏定義int壓入棧并取消它(指的是宏)的定義,如此一來,int的本來含義便獲得了恢復,即int仍代表int。使用完畢后將宏定義int彈出棧,恢復宏定義即int代表double。

轉載自:
1、https://blog.csdn.net/MoreWindows/article/details/6697488
2、https://blog.csdn.net/ivan_ljf/article/details/8787189
感謝優秀博主的分享。

總結

以上是生活随笔為你收集整理的ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。