乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C語言的宏定義用起來有什么要注意的?為什么很多宏用do{}while(0)包圍?

       山峰云繞 2019-07-15

      https://www.toutiao.com/a6713691650176057611/

      謝邀。

      C語言中的 define 宏定義可以像函數(shù)那樣接收參數(shù)(這種宏定義常被稱作“函數(shù)式宏定義”),不過不能像函數(shù)那樣提供參數(shù)的類型檢查,這個(gè)特點(diǎn)在有些程序員看來是不安全的。

      C語言中的“函數(shù)式宏定義”

      但是,函數(shù)式宏定義不關(guān)心參數(shù)類型這個(gè)特點(diǎn),有時(shí)候也會被利用起來,寫出一些適用性更廣的C語言代碼,例如:

      上面這段C語言宏定義代碼實(shí)現(xiàn)了一個(gè) max() 方法,它接收兩個(gè)參數(shù),并返回較大的那個(gè)參數(shù),max() 方法不關(guān)心參數(shù)的類型,因此 __a 和 __b 可以是 int 型的,也可以是 char 型或者 double 型以及其他數(shù)據(jù)類型的。

      如果使用 max() 方法提供的功能以C語言函數(shù)的方式來寫,就稍顯麻煩些了,程序員不得不為每一種數(shù)據(jù)類型實(shí)現(xiàn)一個(gè) max() 函數(shù)。更加糟糕的是,C語言并不支持函數(shù)的重載,因此 max() 這個(gè)函數(shù)名一旦被使用,其他函數(shù)就不能再使用了,因此相關(guān)的C語言代碼可能是下面這樣的:

      這樣對比起來,顯然使用 define 宏來定義 max() 方法更加方便一些。不過,C語言中的宏定義不提供參數(shù)類型檢查的確也是一個(gè)缺點(diǎn),它可能會導(dǎo)致程序的不安全,讀者不應(yīng)忽視這一點(diǎn)。因此如果不是必須要使用 define 宏定義才能解決問題,應(yīng)該盡可能的使用函數(shù),若是希望能夠得到較高效率的代碼,可以使用 inline 函數(shù)。

      關(guān)于 inline 函數(shù),我之前的文章較為詳細(xì)的討論過。

      使用C語言中宏定義的注意事項(xiàng)

      C語言中的“函數(shù)式宏定義”雖然使用起來很像函數(shù),但它實(shí)際上并不是函數(shù),讀者千萬不能忽視這一點(diǎn),不然可能會寫出具有隱患,甚至嚴(yán)重錯(cuò)誤的C語言程序。請看下面這個(gè)例子:

      上面這段C語言代碼編譯并執(zhí)行,會輸出什么呢?

      在 main() 函數(shù)中,變量 a 和 b 都被初始化為 2。接著調(diào)用了 max() 宏,傳遞的參數(shù)分別是 ++a 和 b,粗略來看,此時(shí)執(zhí)行 max(++a, b),就相當(dāng)于執(zhí)行 max(3, 2),那上面這段C語言程序會輸出 3, 2, 3 了?得到答案最簡單粗暴的方法就是編譯并執(zhí)行這段代碼,請看:

      沒有經(jīng)驗(yàn)的讀者看到實(shí)際輸出估計(jì)會大吃一驚,a 和 m 怎么不是 3 而是 4 呢?并沒有第二處給 a 再加一啊?上一節(jié)曾討論,編譯器會將C語言中的宏定義展開到被調(diào)用處,而不是像函數(shù)那樣編譯后,再通過 call 指令調(diào)用。使用 gcc -E 命令查看編譯器將上述C語言代碼預(yù)處理后的代碼,得到如下結(jié)果,請看:

      顯然,這里就是C語言中“函數(shù)式宏定義”的注意事項(xiàng)了,傳遞給 max() 的參數(shù) ++a 會被展開到宏定義中所有的 __a 處,這就解釋了為何 a 和 m 最后都等于 4 而不是 3 了。

      “函數(shù)式宏定義”還有其他與真正函數(shù)不同的地方,例如“函數(shù)式宏定義”就不適合用于遞歸等。

      使用 do{}while(0)包裹代碼

      盡管C語言中的“函數(shù)式宏定義”和真正的函數(shù)相比有一些缺點(diǎn),但只要小心使用還是會顯著提高代碼的執(zhí)行效率的,畢竟省去了分配和釋放棧幀、傳參、傳返回值等一系列工作。正因?yàn)槿绱?,Linux 內(nèi)核中有相當(dāng)多的方法是使用 define 宏定義實(shí)現(xiàn)的,并且,在內(nèi)核C語言代碼中,“函數(shù)式宏定義”經(jīng)常借助 do{}while(0) 實(shí)現(xiàn),例如:

      為什么要用 do{}while(0) 包裹C語言代碼呢?不使用 do{}while(0) 包裹起來有什么不好嗎?請看下面這幾行C語言代碼:

      宏定義被編譯器展開后,會產(chǎn)生下面這樣的C語言代碼:

      這可能就與程序員的意圖不一致了,這種情況下__release(lock); 并沒有在 if(cond) 的作用范圍內(nèi)??赡茏x者會說,那像函數(shù)一樣,使用 {} 包裹代碼不就可以了嗎?請?jiān)賮砜纯聪旅孢@幾行C語言代碼:

      問題就出在 spin_unlock(lock); 后面的這個(gè)分號“;”,如果不寫就不像函數(shù)調(diào)用,如果寫了就會引發(fā)語法錯(cuò)誤——if 語句會被這個(gè)“;”提前結(jié)束,else 無法與其配對。這么看來,在C語言的“函數(shù)式宏定義”中使用 do{}while(0) 包裹C語言代碼顯然就是一個(gè)不錯(cuò)的方法了。

      小結(jié)

      “函數(shù)式宏定義”并不是真正的函數(shù),它與真正的函數(shù)是有區(qū)別的,如果弄不清楚這一點(diǎn),很容易迷惑。在最后,我們一起分析了常用 do{}while(0) 包裹宏定義的代碼的原因,讀者今后在C語言程序開發(fā)中,也可以使用該技巧。



      https://www.toutiao.com/a6713691650176057611/

      宏定義是一種替換類型的語句,屬于低安全性操作,所以在設(shè)計(jì)里面宏一般用于數(shù)值替換,在不得不進(jìn)行函數(shù)動態(tài)鏈接的時(shí)候才會使用宏函數(shù)。

      在能不使用宏的情況下,盡量避免使用宏,因?yàn)楹甑拿钤趨R編中被直接替換掉,甚至被優(yōu)化掉,所以難以進(jìn)行debug。

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多