幾個難懂的 C 語言宏[還是沒搞清楚]
可變參數宏
有些時候定義一個宏來代替某個函數 但是這個函數是可變參數的話 那就需要考慮辦法了
定義方法如下
CODE
#define PRINT(...) printf(__VA_ARGS__)
#include <stdio.h>
int main(){
PRINT("%d %s %s",1,"吃飯了嗎 smile MM:)","\n");
return 0;
}
宏組合
也就是## 和 #的用法
## 是串連符號 串連兩個宏
#是把名字代替成字串
如下
CODE
#define s5(a) supper_ ## a
#include <stdio.h>
void supper_printf(const char* p )
{
printf("this is supper printf:\n%s\n",a);
}
int main()
{
s5(printf)("hello owrld");
return 0;
}
#用法如下
#include <stdio.h>
#define s(p) #p
int main(){
printf(s(p)"\n");
return 0;
}
運行一下就知道了
--------------------------------------------------
#pragma once
#ifndef _MALLOC_SAFE_H_
#define _MALLOC_SAFE_H_
#include <stdio.h>
#include <string>
//#define malloc3(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, # __LINE__) )
#define malloc(size) ( malloc2(size, __LINE__) )
#define malloc_line(size, line) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, #line) )
#define free(buf) ( free_fast_safe(buf) )
//一個簡單的快速檢測方式
void * malloc_fast_safe(int len, const char * c__FILE__, const char * c__FUNCTION__, const char * c__LINE__);
void free_fast_safe(void * p);
#endif
--------------------------------------------------
還是不行,要這樣
#pragma once
#ifndef _MALLOC_SAFE_H_
#define _MALLOC_SAFE_H_
#include <stdio.h>
#include <string>
//宏裡面轉換成字串還是很囉嗦,要用兩級宏加 "#" 來處理
#define __STRINGIFY__(x) #x
#define __TOSTRING__(x) __STRINGIFY__(x)
//#define malloc(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, #__LINE__) )
#define malloc(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, __TOSTRING__(__LINE__)) )
#define free(buf) ( free_fast_safe(buf) )
//一個簡單的快速檢測方式
void * malloc_fast_safe(int len, const char * c__FILE__, const char * c__FUNCTION__, const char * c__LINE__);
void free_fast_safe(void * p);
#endif
參考自 google "__LINE__ 字串"
http://www.cppblog.com/heath/archive/2008/08/05/58046.html
--------------------------------------------------
使用__FILE__和__LINE__定位錯誤
[前言:使用__FILE__和__LINE__來定位錯誤已經屢見不鮮,然而其中一些道理又有幾個人仔細探究過。本文參考了Curtis Krauskopf的一篇名為Using __FILE__ and __LINE__ to Report Errors的文章,希望達到解惑之效。]
問題:當執行階段錯誤產生時,我怎樣才能得到包含C++檔案名稱和行號的字串資訊?
回答:在C++中的__FILE__先行編譯指標包含了被編譯的檔案名稱,而__LINE__則包含了原始碼的行號。__FILE__和__LINE__的前後都包含了兩個底線,讓我們仔細看看__FILE__所包含的每個字元:
_ _ F I L E _ _
下面展示了在控制台程式中如果顯示檔案名稱和程式碼號。
#include <stdio.h>
int main(int , char**)
{
printf("This fake error is in %s on line %d\n", __FILE__, __LINE__);
return 0;
}
輸出結果:
This fake error is in c:\temp\test.cpp on line 5
讓我們更上一層樓
我想通過一個通用函數error()來報告錯誤,以使當某個錯誤發生時我能設定斷點以及隔離錯誤處理(例如,在螢幕上列印錯誤資訊或者寫入日誌)。因此,函數的原型應該是這樣的吧:
void error(const char *file, const unsigned long line, const char *msg);
調用方式如下:
error(__FILE__, __LINE__, "my error message");
預先處理魔法
這裡有三個問題需要解決:
- __FILE__和__LINE__在每次調用error時作為參數傳入。
- __FILE和__LINE__前後的底線很容易被遺忘,從而導致編譯錯誤。
- __LINE__是一個整數,這無疑增加了error函數的複雜度。我絕不想直接使用整型的__LINE__,而通常都是將轉換為字串列印到螢幕或寫入記錄檔。
__FILE__和__LINE__應該被自動處理,而非每次作為參數傳遞給error,這樣會讓error的使用者感覺更爽些,它的形式可能是下面這樣:
error(AT, "my error message");
我希望上面的宏AT展開為:"c:\temp\test.cpp:5"。而新的error函數則變成:
void error(const char *location, const char *msg);
因為Borland C++ Builder編譯器能夠自動合并相鄰的字串,因此我把AT寫成下面這樣:
#define AT __FILE__ ":" __LINE__
然而它卻罷工了,因為__LINE__被擴充成了整數而非字串,所以宏展開後變成:
"c:\temp\test.cpp" ":" 5
這是一個無效的字串,因為末尾有一個未被雙引號包含的整數。
怎麼辦?別著急,一個特殊的先行編譯指標“#”能夠幫我們將一個變數轉換成字串。所以重新定義宏:
#define AT __FILE__ ":" #__LINE__
嘿嘿,這樣總行了吧。別高興得太早,這樣也是不行的。因為編譯器會抱怨#是個無效字元。其實,問題是#先行編譯指標只有這樣使用才會
被正確識別:
#define symbol(X) #X
因此,我把代碼改為:
#define STRINGIFY(x) #x
#define AT __FILE__ ":" STRINGIFY(__LINE__)
然而,奇怪的結果產生了,__LINE__居然被作為了輸出的一部分:
c:\temp\test.cpp:__LINE__: fake error
解決方案是再用一個宏來封裝STRINGIFY():
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
OK,我們用下面的代碼來試試:
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
void error(const char *location, const char *msg)
{
printf("Error at %s: %s\n", location, msg);
}
int main(int , char**)
{
error(AT, "fake error");
return 0;
}
輸出結果:
Error at c:\temp\test\test.cpp:11: fake error
Visual Studio下的實踐
在《Windows核心編程》中,Jeffrey Richter提供了下面的宏在編譯期輸出有用資訊:
#define chSTR2(x) #x
#define chSTR(x) chSTR2(x)
#define chMSG(desc) message(__FILE__ "(" chSTR(__LINE__) "):" #desc)
message是一個先行編譯指令,上面宏的使用方法是:
#pragma chMSG(Fix this later)
結論
- 先行編譯指標__FILE__和__LINE__能夠提供有用的資訊。
- __LINE__的處理方式遠比我們想象的要複雜。
- __FILE__被處理成字串,給我們帶來了不少方便。
posted on 2008-08-05 11:55