新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > C/C++中宏定義的經(jīng)典運(yùn)用

        C/C++中宏定義的經(jīng)典運(yùn)用

        作者: 時(shí)間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
        在C語言中宏定義是比較有用的技巧,在Linux源碼中經(jīng)常使用一些宏定義,比如宏container_of()等都是經(jīng)典的宏定義表示方式。在C++不再主張使用宏定義,但是宏定義實(shí)際上卻是是一個(gè)非常有用的手段。實(shí)質(zhì)上宏定義能夠搞定的實(shí)現(xiàn)采用其它的實(shí)現(xiàn)也是可以的,宏定義的作用是簡(jiǎn)單的替代作用,掌握這個(gè)是理解的關(guān)鍵,以前在沒有代碼閱讀量的時(shí)候總是以為宏定義就是簡(jiǎn)單的定義一些常量什么的,實(shí)質(zhì)上不然,宏定義完全可以寫成函數(shù)的形式,但是宏定義和函數(shù)有一定的差別,函數(shù)的調(diào)用一般采用棧的方式實(shí)現(xiàn),這時(shí)候存在局部變量,形參、實(shí)參等問題,如果不理解C語言的本質(zhì),很多時(shí)候非常容易搞錯(cuò),但是宏定義則不然,宏定義沒有調(diào)用的過程,宏的實(shí)現(xiàn)僅僅是一個(gè)替換過程,不用壓棧出棧,宏實(shí)現(xiàn)的類似函數(shù)修改的就是當(dāng)前區(qū)域中的變量,不是局部變量。這也是一些較深層次的問題,在剛學(xué)習(xí)C語言的時(shí)候很多人只要看見類似于函數(shù)的形式都認(rèn)為是函數(shù),實(shí)質(zhì)上不一定,很有可能就是采用宏定義實(shí)現(xiàn)的類函數(shù),這時(shí)候就可能導(dǎo)致所謂的形參實(shí)參問題發(fā)生較大的變化。關(guān)于宏的問題在面試筆試的過程中、寫代碼的過程中都是非常有用的部分,我就不再做介紹。

        今天看了一遍博客《Reduce C-language coding errors with X macros》,感覺文章寫得非常的好,也對(duì)自己寫代碼有了一定的幫助,所以就將該文章用我自己的語言,寫出來和大家分享分享吧。

        本文引用地址:http://www.104case.com/article/201612/324488.htm

        在嵌入式實(shí)時(shí)操作系統(tǒng)中,經(jīng)常將系統(tǒng)分成很多層次,很多個(gè)模塊,每一個(gè)模塊都有自己的初始化過程,這時(shí)候我們一般采用的形式如下所示:

        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,
        };

        這種實(shí)現(xiàn)方法是比較常見的實(shí)現(xiàn)方式,但是這種方法的缺點(diǎn)是所有的初始化過程是按照一定的順序的,而且不能隨機(jī)的初始化,因此如果在編碼的過程中將狀態(tài)號(hào)與初始化函數(shù)對(duì)應(yīng)錯(cuò)誤,將出現(xiàn)比較難以發(fā)現(xiàn)的錯(cuò)誤,這種錯(cuò)誤經(jīng)常出現(xiàn),當(dāng)然有些編譯器以及支持隨機(jī)的初始化過程,但是并不具有通用性,而且這種實(shí)現(xiàn)方式代碼比較多,能不能采用宏定義的方式簡(jiǎn)化代碼量呢?當(dāng)然是可以的,采用類似于函數(shù)的宏定義就可以實(shí)現(xiàn),具體的實(shí)現(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
        };

        上面這種實(shí)現(xiàn)方式的優(yōu)點(diǎn)是運(yùn)用了宏定義簡(jiǎn)少代碼量。我做一個(gè)簡(jiǎn)要的分析,首先采用宏定義定義了一組ENYRT,其中包含兩個(gè)參數(shù),分別是狀態(tài)號(hào)STATE_N,和狀態(tài)對(duì)應(yīng)的初始化函數(shù),這種實(shí)現(xiàn)方式能夠避免上面所謂的狀態(tài)號(hào)與函數(shù)對(duì)應(yīng)錯(cuò)誤的問題,因?yàn)樵诤甓x的過程中一般都會(huì)認(rèn)真的確定各種接口,對(duì)應(yīng)好了只需要定義相關(guān)的函數(shù)就可以啦。在enum中采用了#define和#undef來限定這一組宏定義的作用范圍,在個(gè)作用域中,ENTRY(a,b)是表示“a,”,需要注意不能忽略a后的,因?yàn)檫@就是在enum中定義變量后要添加的符號(hào),我想大家應(yīng)該知道enum{a,b,c,d}每一個(gè)成員后面都包含","的特性的。也就是說在這作用域中,ENTRY(a,b)被替換為"a,",那么這時(shí)候STATE_TABLE就被替換為STATE_0,STATE_1等,然后和NUM_STATES就組成了第一個(gè)例程中的enum結(jié)構(gòu)。而在p_func_t jumptable[NUM_STATES]仍然采用了了STATE_TABLE,由于采用了#define和#undef限定了宏的作用范圍,這時(shí)的ENTRY(a,b)將被替代為“b,”,也就是func_0,func_1等,這樣也就完成了函數(shù)指針數(shù)組的初始化過程,這樣的初始化能夠減少狀態(tài)號(hào)與初始化函數(shù)對(duì)應(yīng)出錯(cuò)的情況。

        這樣的實(shí)現(xiàn)也可以認(rèn)為是宏定義的巧妙運(yùn)用,但是這種方法還是存在一些問題,因?yàn)椴捎?define 和#undef這種方法很可能導(dǎo)致錯(cuò)誤的產(chǎn)生,因?yàn)楹苡锌赡懿荒芎芎玫陌盐者@個(gè)限定作用域的使用方法,這時(shí)候可以采用一種新的類似函數(shù)的實(shí)現(xiàn)方法,可以讓STATE_TABLE帶一個(gè)參數(shù),也就是采用類似命令的形式定義相關(guān)的內(nèi)容:

        typedef void(*p_func_t)(void);

        /*以下產(chǎn)生幾個(gè)常用的命令*/
        /*enum產(chǎn)生*/
        #define EXPAND_AS_ENUM(a,b) a,
        /*初始化表產(chǎn)生*/
        #define EXPAND_AS_INITTABLE(a,b) b,
        /*聲明各個(gè)函數(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
        };

        /*聲明各個(gè)函數(shù)*/
        STATE_TABLE(EXPAND_AS_FUNCDEC)

        /*初始化表*/
        p_func_t inital_table[NUM_STATES] =
        {
        STATE_TABLE(EXPAND_AS_INITTABLE)
        };

        以上實(shí)現(xiàn)方法能夠較好的避免#define和#undef的限定作用域問題,這實(shí)際上采用ENTRY作為參數(shù)傳遞給STATE_TABLE,然后ENTRY可用來實(shí)現(xiàn)不同的指令,這些指令的定義也是一系列的宏定義,這種實(shí)現(xiàn)架構(gòu)能夠比較好的避免缺少聲明等問題。同時(shí)也較少了錯(cuò)誤的產(chǎn)生可能。


        上一頁 1 2 下一頁

        評(píng)論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 凤台县| 沧源| 吴旗县| 临朐县| 安仁县| 厦门市| 鄂温| 尉氏县| 庄浪县| 福清市| 旺苍县| 佛学| 金山区| 武陟县| 秭归县| 丽江市| 昂仁县| 灵寿县| 阳高县| 泗洪县| 金坛市| 安平县| 桐乡市| 交城县| 共和县| 镇雄县| 开封县| 河间市| 苗栗县| 高要市| 馆陶县| 海丰县| 宁城县| 益阳市| 马公市| 阳山县| 申扎县| 丹江口市| 泽库县| 英超| 青冈县|