c語言巨集定義中"#","#@"和"##"的用法
#definemacro(a)#a
#definemacro2(a,b)a##b
#definemacro3(a,b,c)a##b##c
#a, 表示a不再是乙個變數, 而變成了字串"a"
##表示連線, a##b, 表示輸入的引數名為ab, a##b##c同理, 代表變數名為: abc
測試例子:
intx=3;
inty=4;
intxy=10;
intxyz=20;
cstringstr;
outputdebugstring(macro(x));
"%d",macro2(x,y));
outputdebugstring(str);
"%d",macro3(x,y,z));
outputdebugstring(str);
輸出結果為:x10
20第乙個為x, marco(x), x變成了"x"字串
第二個為10, macro(x,y), 就是變數xy
第三個為20, macro(x,y,z), 就是變數xyz
#把巨集引數變為乙個字串,#@把巨集引數變為乙個字元,##把兩個巨集引數貼合在一起。
#include <>
#include <>
#define str(s) #s與引數之間可以有空格
#define tochar(c) #@c
#define cons(a,b) int(a##e##b與引數之間可以有空格
int main(void)
需要注意的是凡巨集定義裡有用'#'或'##'的地方巨集引數是不會再展開的。
#define a (2)
#define str(s) br##define cons(a,b) int(a##e##b)
printf("int max: %s\n", str(int_max));
這行會被展開為:
printf("int max: %s\n", "int_max");
printf("%s\n", cons(a, a));
這一行被展開為:
printf("%s\n", int(aea));
int_max和a都不會再被展開, 然而解決這個問題的方法很簡單,多加一層中間轉換巨集。加這層巨集的用意是把所有巨集的引數在這層裡全部展開,那麼在轉換巨集裡的那乙個巨集(_str)就能得到正確的巨集引數。
#define a2)
#define _str(s) br##define str(s) _str(s轉換巨集
#define _cons(a,b) int(a##e##b)
#define cons(a,b) _cons(a,b) // 轉換巨集
printf("int max: %s\n", str(int_max));
輸出為:int max: 0x7fffffff
str(int_max) --> _str(0x7fffffff) --> "0x7fffffff"
printf("%d\n", cons(a, a));
輸出為:200
cons(a, a) --> _cons((2), (2)) --> int((2)e(2))
以下為minix3作業系統相關的源**:
#ifdef _ansi
#define __str(x) # x
#define __xstr(x) __str(x轉換巨集
_prototype( void __bad_assertion, (const char *_mess) );
#define assert(expr)((expr)? (void)0 : \
bad_assertion("assertion \"" #expr \
failed, file " __xstr(__file__) \
line " __xstr(__line__) "\n"))
#define ___anonymous1(type, var, line) type var##line
#define __anonymous0(type, lineanonymous1(type, _anonymous, line)
#define anonymous(typeanonymous0(type, __line__)
例:anonymous(static int); 即: static int _anonymous70; 70表示該行行號;
第一層:anonymous(static int); --> __anonymous0(static int, __line__);
第二層》 ___anonymous1(static int, _anonymous, 70);
第三層》 static int _anonymous70;
即每次只能解開當前層的巨集,所以__line__在第二層才能被解開;
#define fill(a)
enum idd;
typedef struct msg
msg;
msg _msg = ;
相當於:
msg _msg = , };
#define _get_file_name(f) #f
#define get_file_name(f) _get_file_name(f) // 轉換巨集
static char file_name = get_file_name(__file__);
#define _type_buf_size(type) sizeof #type
#define type_buf_size(type) _type_buf_size(type)
char buf[type_buf_size(int_max)];
--> char buf[_type_buf_size(0x7fffffff)];
--> char buf[sizeof "0x7fffffff"];
這裡相當於:
char buf[11];
編寫**的過程中,經常會輸出一些除錯資訊到螢幕上,一般會呼叫printf這類的函式。
但是當除錯解決之後,我們需要手工將這些地方刪除或者注釋掉。
再這次的專案中就用到類似問題,為了除錯程式,再一些地方輸出了很多的資訊,隨著專案的除錯,輸出的資訊越來越多。於是就面臨著,如何處理這些輸出資訊的語句。
簡單刪掉,不僅有一定的工作量,而且也不能保證之後就不出現問題,出現問題後這些資訊還是有用的。
不去掉,帶著除錯資訊就上線,這是明顯不允許的。
於是就想到了乙個可行的辦法。如下:
void myprintf(char* fmt, ...)
#ifdef debug
#define printf(fmt, args...) myprintf(fmt, ##args)
#endif
除錯階段帶著debug除錯,正式上線就可以把printf變成乙個空函式了。
這樣做的乙個潛在風險是可能會導致默寫glib函式需要呼叫printf輸出錯誤log也給取消掉了。
令人欣慰的是,大部分glib呼叫的應該是fprintf。
雖然問題解決了,但是我對args...以及##args還是不太了解。上網找了些gcc手冊的資料如下:
帶有可變引數的巨集(macros with a variable number of arguments)
IO,IOR,IOW,IOWR巨集的用法與解析
io,ior,iow,iowr巨集的用法與解析.txt41滴水能穿石,只因為它永遠打擊同一點。42火柴如果躲避燃燒的痛苦,它的一生都將黯淡無光。巨集 io,ior,iow,iowr 巨集的用法與解析 2010 10 26 11 27 10 標籤 it 分類 人生 在驅動程式裡,ioctl 函式上傳送...
C語言函式和巨集定義
一 目的和要求 1 掌握函式的定義方法和呼叫規則。2 掌握c語言程式中主調函式和被呼叫函式之間進行資料傳遞的規則。3 了解函式的返回值及它的型別,並正確使用它。4 了解區域性變數和全域性變數的作用域及它們與儲存分類的關係,理解變數的存在性和可見性的概念。5 練習遞迴函式的使用。6 理解巨集的概念,掌...
全域性變數巨集定義 精
以下是如何定義全域性變數。眾所周知,全域性變數應該是得到記憶體分配且可以被其他模組通過c語言中extern關鍵字呼叫的變數。因此,必須在 c 和 h 檔案中定義。這種重複的定義很容易導致錯誤。error e46 undefined external serbfr referred in zlg522...