之前也看過一些c語言巨集的使用,特別是對_t 以及 text 巨集的實現也比較感興趣,但是之前對_t,text巨集的實現也是一知半解,沒有徹底搞明白,週末在寫另外一篇部落格(時恰好又用到了巨集,所以想好好把這塊學習整理下。
#的作用是把乙個token(標記)變成乙個字串,也就是使用""把token包含起來
下面是比較常用的用法
#define name_to_str(name) (#name)
下面這個可以支援轉換成unicode字串
#define name_to_str(name) (_t(#name))
_tprintf(name_to_str(name_to_string)); // 輸出字串"name_to_string"
#define make_pair(id) (std::pair(id, _t(#id)))
##的作用是把兩個token貼合在一起,比如下面cons巨集用來定義科學計數法的整數
#define cons(a,b) int(a##e##b)
printf("%d\n", cons(2,3)); // 2e3 輸出:2000
還有一些用法是用來定義變數,比如
#define def_var(type,name) type name##_##type##_type
def_var(int, age); -> int age_int_type;
1. 非'#'和'##'的情況
#define tow (2)
#define mul(a,b) (a*b)
printf("%d*%d=%d\n", tow, tow, mul(tow,tow));
這行的巨集會被展開為:
printf("%d*%d=%d\n", (2), (2), ((2)*(2)));
mul裡的引數tow會被展開為(2).
2. 當有'#'或'##'的時候
#define a (2)
#define str(s) #s
#define cons(a,b) int(a##e##b)
printf("int max: %s\n", str(int_max)); // int_max #include
這行會被展開為:
printf("int max: %s\n", "int_max");
printf("%s\n", cons(a, a)); // compile error
這一行則是:
printf("%s\n", int(aea));
int_max和a都不會再被展開, 然而解決這個問題的方法很簡單. 加多一層中間轉換巨集.
加這層巨集的用意是把所有巨集的引數在這層裡全部展開, 那麼在轉換巨集裡的那乙個巨集(_str)就能得到正確的巨集引數.
#define a (2)
#define _str(s) #s
#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,int型的最大值,為乙個變數 #include
輸出為: int max: 0x7fffffff
str(int_max) --> _str(0x7fffffff) 然後再轉換成字串;
printf("%d\n", cons(a, a));
輸出為:200
cons(a, a) --> _cons((2), (2)) --> int((2)e(2))
通過上面的說明已經明白了巨集展開的規則了,那麼之前寫的name_to_str就存在問題了。不能在巨集引數中放入有巨集的引數。
第一種情況:
#define name_to_str(name) (_t(#name))
_tprintf(name_to_str(name_to_string)); // 輸出字串"name_to_string"
測試沒有問題。
第二種情況:
#define user_name zhangsan
#define name_to_str(name) (_t(#name))
_tprintf(name_to_str(user_name)); // 輸出字串"user_name",和預期的"zhangsan"不符合
所以也要通過增加一層中間轉換巨集,實現如下:
#define _name_to_str(name) (_t(#name))
#define name_to_str(name) (_name_to_str(name))
#define user_name zhangsan
_tprintf(name_to_str(user_name)); // 輸出字串"zhangsan"
winnt.h中對text的實現如下:
#ifdef unicode
#define __text(quote) l##quote
#define text(quote) __text(quote)
#endif
可見和我們之前講解name_to_str巨集的思路一樣,也需要增加一層中間巨集,不然也不能傳入含有巨集的引數
...在c巨集中稱為variadic macro,也就是變參巨集。簡單看下下面的使用方式吧
void makelog(const char *pszfile, int nline, const char *pszfunction,
const char *fmt, ...) ;
_vsnprintf_s(szdata, nmaxlen - 1, _truncate, fmt, ap);
va_end(ap);
//logfile(pszfile, nline, pszfunction, szdata);
}#define logformat(fmt, ...) makelog(__file__,__line__,__function__,fmt, ##__va_args__)
logformat("%s %s", "username:", "zhangsan");
參考文章: C語言巨集中 和 的用法
c語言巨集中 和 的用法 一 一般用法 我們使用 把巨集引數變為乙個字串,用 把兩個巨集引數貼合在一起.用法 include include using namespace std define str s s define cons a,b int a e b int main printf st...
C語言 巨集中 和 的用法
巨集中 和 的用法 一 一般用法 我們使用 把巨集引數變為乙個字串,用 把兩個巨集引數貼合在一起.用法 include include using namespace std define str s s define cons a,b int a e b int main 二 當巨集引數是另乙個巨...
C語言巨集中 和 的用法
一 一般用法 我們使用 把巨集引數變為乙個字串,用 把兩個巨集引數貼合在一起.用法 include include using namespace std define str s s define cons a,b int a e b int main printf str vck 輸出字串 vc...