宏因?yàn)槠涓鞣N副作用而備受詬病,就像goto一樣,有些產(chǎn)品談宏色變。但是語言特性本身并無善惡之分,其善惡在于使用者。有時(shí)候使用某些語言特性,能夠非常好的解決一些編程中的難題。本文就使用宏來解決一個(gè)比較棘手的問題。
有一個(gè)函數(shù),原型如下:
// a.h
void TEST(unsigned int a, unsigned int b, unsigned int c);
在UT測試中,要對這個(gè)函數(shù)打樁,打樁成了一個(gè)宏,實(shí)現(xiàn)如下:
// b.h
#define TEST(a, b, c) a = b + c
在main函數(shù)中如下調(diào)用:
// mian.c
int main()
{
int a = 5, b = 3, c = 8;
TEST(a, b, c);
return 0;
}
在編譯時(shí),會(huì)根據(jù)是否是UT工程決定使用a.h還是b.h。
當(dāng)使用a.h時(shí)會(huì)有一個(gè)告警,因?yàn)?code>TEST函數(shù)的定義形參要求是unsigned int,而實(shí)參是int。因?yàn)槭褂?code>TEST的地方很多,且情況比較復(fù)雜,只能使用類型強(qiáng)轉(zhuǎn)清除這個(gè)告警。
改成如下形式,UT工程編譯不過(原因是宏展開后,等式的左值不能有強(qiáng)轉(zhuǎn))
// mian.c
int main()
{
int a = 5, b = 3, c = 8;
TEST((unsigned int)a, (unsigned int)b, (unsigned int)c);
return 0;
}
怎么辦?
好像沒有什么好辦法,試著將TEST重定義,如下:
#ifdef _UT_
#define MY_TEST(a, b, c) TEST(a, b, c)
#else
#define MY_TEST(a, b, c) TEST((unsigned int)a, (unsigned int)b, (unsigned int)c)
#endif
int main()
{
int a = 5, b = 3, c = 8;
MY_TEST(a, b, c);
return 0;
}
問題看似解決,但是伴隨的是成千上萬出的TEST調(diào)用要換成MY_TEST的調(diào)用,并且后續(xù)開發(fā)人員必須要遵守使用MY_TEST的規(guī)則,否則就會(huì)出錯(cuò)。
有沒有更好的辦法,使得影響降至最小?仔細(xì)想下,UT工程并不關(guān)心數(shù)據(jù)類型的轉(zhuǎn)換,如果能夠?qū)㈩愋娃D(zhuǎn)換那一部分((unsigned int))在宏展開時(shí)替換掉就能解決問題。
如果能夠讓(unsigned int)前面拼接一個(gè)符號(hào)組成一個(gè)宏函數(shù),然后定義這個(gè)宏函數(shù)的實(shí)現(xiàn)為空即可,如下:
#define DUMMY(...)
#define TEST(a, b, c) DUMMY#a = DUMMY#b + DUMMY#c
對于TEST((unsigned int)a, (unsigned int)b, (unsigned int)c);期望展開后是DUMMY(unsigned int)a = DUMMY(unsigned int)b + DUMMY(unsigned int)c,DUMMY(unsigned int)為空,則替換后為a = b + c,完美。
但是,上面的做法是錯(cuò)的,編譯不過,因?yàn)槭褂?code>#展開后的形式是DUMMY"(unsigned int)a" = DUMMY"(unsigned int)b" + DUMMY"(unsigned int)c"。
正確的寫法是去掉#,但一定要在DUMMY和宏參數(shù)間加上空格,如下:
#define DUMMY(...)
#define TEST(a, b, c) DUMMY a = DUMMY b + DUMMY c
至此,使用宏完美地解決了這個(gè)看似無解的問題。