C語言巨集中 和 的用法以及巨集展開規則

2021-10-23 06:16:50 字數 3226 閱讀 3819

之前也看過一些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...