C/C++中宏定義的經(jīng)典運用
今天看了一遍博客《Reduce C-language coding errors with X macros》,感覺文章寫得非常的好,也對自己寫代碼有了一定的幫助,所以就將該文章用我自己的語言,寫出來和大家分享分享吧。
本文引用地址:http://m.butianyuan.cn/article/201612/324488.htm在嵌入式實時操作系統(tǒng)中,經(jīng)常將系統(tǒng)分成很多層次,很多個模塊,每一個模塊都有自己的初始化過程,這時候我們一般采用的形式如下所示:
typedef void(*p_func_t)(void);
enum
{
STATE_0,
STATE_1,
STATE_2,
...
STATE_M,
NUM_STATES
};
p_func_t inital_table[NUM_STATES]
{
func_0,
func_1,
func_2,
...
func_M,
};
這種實現(xiàn)方法是比較常見的實現(xiàn)方式,但是這種方法的缺點是所有的初始化過程是按照一定的順序的,而且不能隨機的初始化,因此如果在編碼的過程中將狀態(tài)號與初始化函數(shù)對應(yīng)錯誤,將出現(xiàn)比較難以發(fā)現(xiàn)的錯誤,這種錯誤經(jīng)常出現(xiàn),當(dāng)然有些編譯器以及支持隨機的初始化過程,但是并不具有通用性,而且這種實現(xiàn)方式代碼比較多,能不能采用宏定義的方式簡化代碼量呢?當(dāng)然是可以的,采用類似于函數(shù)的宏定義就可以實現(xiàn),具體的實現(xiàn)如下:
typedef void(*p_func_t)(void);
#define STATE_TABLE
ENTRY(STATE_0,func_0)
ENTRY(STATE_1,func_1)
ENTRY(STATE_2,func_2)
ENTRY(STATE_3,func_3)
ENTRY(STATE_4,func_4)
enum{
#define ENTRY(a,b) a,
STATE_TABLE
#undef ENTRY
NUM_STATES
};
p_func_t inital_table[NUM_STATES] =
{
#define ENTRY(a,b) b,
STATE_TABLE
#undef ENTRY
};
上面這種實現(xiàn)方式的優(yōu)點是運用了宏定義簡少代碼量。我做一個簡要的分析,首先采用宏定義定義了一組ENYRT,其中包含兩個參數(shù),分別是狀態(tài)號STATE_N,和狀態(tài)對應(yīng)的初始化函數(shù),這種實現(xiàn)方式能夠避免上面所謂的狀態(tài)號與函數(shù)對應(yīng)錯誤的問題,因為在宏定義的過程中一般都會認(rèn)真的確定各種接口,對應(yīng)好了只需要定義相關(guān)的函數(shù)就可以啦。在enum中采用了#define和#undef來限定這一組宏定義的作用范圍,在個作用域中,ENTRY(a,b)是表示“a,”,需要注意不能忽略a后的,因為這就是在enum中定義變量后要添加的符號,我想大家應(yīng)該知道enum{a,b,c,d}每一個成員后面都包含","的特性的。也就是說在這作用域中,ENTRY(a,b)被替換為"a,",那么這時候STATE_TABLE就被替換為STATE_0,STATE_1等,然后和NUM_STATES就組成了第一個例程中的enum結(jié)構(gòu)。而在p_func_t jumptable[NUM_STATES]仍然采用了了STATE_TABLE,由于采用了#define和#undef限定了宏的作用范圍,這時的ENTRY(a,b)將被替代為“b,”,也就是func_0,func_1等,這樣也就完成了函數(shù)指針數(shù)組的初始化過程,這樣的初始化能夠減少狀態(tài)號與初始化函數(shù)對應(yīng)出錯的情況。
這樣的實現(xiàn)也可以認(rèn)為是宏定義的巧妙運用,但是這種方法還是存在一些問題,因為采用#define 和#undef這種方法很可能導(dǎo)致錯誤的產(chǎn)生,因為很有可能不能很好的把握這個限定作用域的使用方法,這時候可以采用一種新的類似函數(shù)的實現(xiàn)方法,可以讓STATE_TABLE帶一個參數(shù),也就是采用類似命令的形式定義相關(guān)的內(nèi)容:
typedef void(*p_func_t)(void);
/*以下產(chǎn)生幾個常用的命令*/
/*enum產(chǎn)生*/
#define EXPAND_AS_ENUM(a,b) a,
/*初始化表產(chǎn)生*/
#define EXPAND_AS_INITTABLE(a,b) b,
/*聲明各個函數(shù)*/
#define EXPAND_AS_FUNCDEC(a,b) void b(void);
/*將STATE_TABLE的參數(shù)就是具體的命令*/
#define STATE_TABLE(ENTRY)
ENTRY(STATE_0,func_0)
ENTRY(STATE_1,func_1)
ENTRY(STATE_2,func_2)
ENTRY(STATE_3,func_3)
ENTRY(STATE_4,func_4)
/*定義enum*/
enum{
STATE_TABLE(EXPAND_AS_ENUM)
NUM_STATES
};
/*聲明各個函數(shù)*/
STATE_TABLE(EXPAND_AS_FUNCDEC)
/*初始化表*/
p_func_t inital_table[NUM_STATES] =
{
STATE_TABLE(EXPAND_AS_INITTABLE)
};
以上實現(xiàn)方法能夠較好的避免#define和#undef的限定作用域問題,這實際上采用ENTRY作為參數(shù)傳遞給STATE_TABLE,然后ENTRY可用來實現(xiàn)不同的指令,這些指令的定義也是一系列的宏定義,這種實現(xiàn)架構(gòu)能夠比較好的避免缺少聲明等問題。同時也較少了錯誤的產(chǎn)生可能。
評論