国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C語言中函數(shù)宏的三種封裝方式詳解

這篇具有很好參考價值的文章主要介紹了C語言中函數(shù)宏的三種封裝方式詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

C語言中函數(shù)宏的三種封裝方式詳解

?

目錄

?編輯

1. 函數(shù)宏介紹

3.?do{...}while(0)?方式

4.?({})?方式

5. 總結


1. 函數(shù)宏介紹

函數(shù)宏,即包含多條語句的宏定義,其通常為某一被頻繁調用的功能的語句封裝,且不想通過函數(shù)方式封裝來降低額外的彈棧壓棧開銷。

函數(shù)宏本質上為宏,可以直接進行定義,例如:

#define?INT_SWAP(a,b)?\
????int?tmp?=?a;????\
????a?=?b;??????????\
????b?=?tmp

但上述的宏具有一個明顯的缺點:當遇到?if、while?等語句且不使用花括號僅調用宏時,實際作用范圍在宏的第一個分號后便結束。即?a = b?和?b = tmp?均不受控制語句所作用。

因此,在工程中,一般使用三種方式來對函數(shù)宏進行封裝,分別為?{}、do{...}while(0)?和?({})。下文將一一對三種方式進行分析,比較各自的優(yōu)劣點。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.?{}?方式

INT_SWAP?宏使用?{}?封裝后形態(tài)如下:

#define?INT_SWAP(a,b)\
{???????????????????\
????int?tmp?=?a;????\
????a?=?b;??????????\
????b?=?tmp;????????\
}

此時,直接調用與在無花括號的控制語句(如?if、while)中調用均能正常運行,例如:

#define?INT_SWAP(a,b)?\
{???????????????????\
????int?tmp?=?a;????\
????a?=?b;??????????\
????b?=?tmp;????????\
}

int?main()
{
?int?var_a?=?1;
?int?var_b?=?2;

?INT_SWAP(var_a,?var_b);
?printf("var_a?=?%d,?var_b?=?%d\n",?var_a,?var_b);???//?var_a?=?2,?var_b?=?1
?
?if?(1)
????INT_SWAP(var_a,?var_b);
?printf("var_a?=?%d,?var_b?=?%d\n",?var_a,?var_b);???//?var_a?=?1,?var_b?=?2
}

但當無花括號的?if?語句存在其他分支(else if、else?等)如:

if?(1)
???INT_SWAP(var_a,?var_b);
else
?printf("hello?world!\n");

會發(fā)現(xiàn)編譯出錯:

...
/mnt/hgfs/share/pr_c/src/main.c:?In?function?‘main’:
/mnt/hgfs/share/pr_c/src/main.c:18:2:?error:?‘else’?without?a?previous?‘if’
??else

這是因為?INT_SWAP(var_a, var_b);?最后的?;?已經(jīng)把?if?的作用域終結了,后續(xù)的?else?當然沒有找到與之匹配的?if?了。

因此,解決方法有兩種,分別為不使用?;(port.1)或規(guī)定必須使用帶花括號的?if(port.2),例如:

/*?port.1?*/
if?(1)
???INT_SWAP(var_a,?var_b)
else
{
????printf("hello?world!\n");
}

/*?port.2?*/
if?(1)
{
???INT_SWAP(var_a,?var_b);
}
else
{
????printf("hello?world!\n");
}

可見,不使用?;?的調用方式無論從程序閱讀還是使用方法方面都是十分別扭的;而規(guī)定必須使用帶花括號的?if?的調用方式有違常理的,因為宏函數(shù)應該適用于任何語法。

優(yōu)缺點總結:

  • 優(yōu)點:簡單粗暴。

  • 缺點:不能在無花括號且有分支的?if?語句中直接調用;能夠不帶?;?直接調用。

3.?do{...}while(0)?方式

INT_SWAP?宏使用?do{...}while(0)?封裝后形態(tài)如下:

#define?INT_SWAP(a,b)???\
do{?????????????????????\
????int?tmp?=?a;????????\
????a?=?b;??????????????\
????b?=?tmp;????????????\
}while(0)

do{...}while(0)?表示只執(zhí)行一遍?{}?內的語句,表象來說與?{}?的功能是一致的。不同的是,do{...}while(0)?可以提前退出函數(shù)宏、整合為一條語句與強制調用時必須使用?;。

由于?do{...}while(0)?實際為 while 循環(huán),因此可以使用關鍵字?break?提前結束循環(huán)。利用該特性,可以為函數(shù)宏添加參數(shù)檢測。例如:

#define?INT_SWAP(a,b)??\
do{?????????????????\
?if?(a?<?0?||?b?<?0)?\
??break;???\
????int?tmp?=?a;?????\
????a?=?b;???????????\
????b?=?tmp;?????????\
}while(0)

由于?do{...}while(0);?實際為一種語法,編譯器會把?do{...}while(0);?認為為一條語句。

因此,do{...}while(0)?方式的函數(shù)宏可以在無花括號且有分支的?if?語句中直接調用。例如:

#define?INT_SWAP(a,b)??\
do{?????????????????\
?if?(a?<?0?||?b?<?0)?\
??break;???\
????int?tmp?=?a;?????\
????a?=?b;???????????\
????b?=?tmp;?????????\
}while(0)

int?main()
{
?int?var_a?=?1;
?int?var_b?=?2;

?if?(1)
????INT_SWAP(var_a,?var_b);
?else
??printf("hello?world!\n");?
?printf("var_a?=?%d,?var_b?=?%d\n",?var_a,?var_b);?//?var_a?=?2,?var_b?=?1

?return?0;
}

C 語言規(guī)定,do{...}while(0)?語法必須使用?;?作為語句結尾。因此不可能存在以下語句的程序出現(xiàn):

if?(1)
???INT_SWAP(var_a,?var_b)
else
{
?printf("hello?world!\n");?
}

優(yōu)缺點總結:

  • 優(yōu)點:支持在無花括號且有分支的?if?語句中直接調用;支持提前退出函數(shù)宏;強制調用時必須使用?;

  • 缺點:無返回值,不能作為表達式的右值使用。

4.?({})?方式

({})?為 GNU C 擴展的語法,非 C 語言的原生語法。

INT_SWAP?宏使用?({})?封裝后形態(tài)如下:

#define?INT_SWAP(a,b)???\
({??????????????????????\
????int?tmp?=?a;????????\
????a?=?b;??????????????\
????b?=?tmp;????????????\
})

與?do{...}while(0)?相同,({})?支持在無花括號且有分支的?if?語句中直接調用。例如:

#define?INT_SWAP(a,b)??\
({?????????????????\
?int?tmp?=?a;????\
?a?=?b;??????????\
?b?=?tmp;????????\
})

int?main()
{
?int?var_a?=?1;
?int?var_b?=?2;
?
?if?(1)
????INT_SWAP(var_a,?var_b);
?else
??printf("hello?world!\n");
?printf("var_a?=?%d,?var_b?=?%d\n",?var_a,?var_b);?//?var_a?=?2,?var_b?=?1
?
?return?0;
}

與?do{...}while(0)?不同的是,({})?不能提前退出函數(shù)宏與支持返回值。({})?畢竟不是 while 循環(huán),不能直接使用?break退出函數(shù)宏是比較容易理解。那支持返回值是什么意思呢?

答案是 C 語言規(guī)定?({})?中的最后一條語句的結果為該雙括號體的返回值。例如:

int?main()
{
?int?a?=?({
??10;
??1000;
?});
?printf("a?=?%d\n",?a);??????//?a?=?1000
}

因此,({})?可以為函數(shù)宏提供返回值。例如:

#define?INT_SWAP(a,b)??\
({?????????????????\
?int?ret?=?0;??\
?if?(a?<?0?||?b?<?0)?\
?{?????\
??ret?=?-1;??\
?}?????\
?else????\
?{?????\
??int?tmp?=?a;????\
??a?=?b;??????????\
??b?=?tmp;????????\
?}?????\
?ret;????\
})

int?main()
{
?int?var_a?=?1;
?int?var_b?=?2;
?
?if?(INT_SWAP(var_a,?var_b)?!=?-1)
??printf("swap?success?!!\n");?????//?swap?success?!!
?else
??printf("swap?fail?!!\n");?
?printf("var_a?=?%d,?var_b?=?%d\n",?var_a,?var_b);?//?var_a?=?2,?var_b?=?1
?
?return?0;
}

可見,此時的?INT_SWAP?宏已與函數(shù)十分接近。

優(yōu)缺點總結:

  • 優(yōu)點:支持在無花括號且有分支的?if?語句中直接調用;有返回值,支持作為表達式的右值。

  • 缺點:不支持提前退出函數(shù)宏;非 C 的原生語法,編譯器可能不支持。

5. 總結

綜上,在?{}do{...}while(0)?和?({})?這三種函數(shù)宏的封裝方式之中,應盡可能不使用?{},考慮兼容性一般選擇使用?do{...}while(0),當需要函數(shù)宏返回時可以考慮使用?({})?或直接定義函數(shù)。文章來源地址http://www.zghlxwxcb.cn/news/detail-431715.html

到了這里,關于C語言中函數(shù)宏的三種封裝方式詳解的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • C語言——字符串、打印字符串的三種方式

    C語言——字符串、打印字符串的三種方式

    字符串( character string )是一個或多個字符的序列,空字符( null character )\\0 標記字符串的結束 字符串以數(shù)組( array )存儲,也就是以空字符(\\0)結尾的 char 類型數(shù)組 用 %s 轉換說明來處理字符串的輸入和輸出 輸入和輸出必須給出字符串的首地址,可以 直接是字符串常量

    2024年02月11日
    瀏覽(21)
  • 計算字符串長度的三種方法(庫函數(shù) 指針 )【詳解】

    計算字符串長度的三種方法(庫函數(shù) 指針 )【詳解】

    求字符串長度簡單來說就是計算一個字符串(字符數(shù)組)中元素的個數(shù)即從數(shù)組頭部計數(shù),直到遇到字符串’\\0’結束符為止, 計數(shù)結果不包括’\\0’. C語言中的庫函數(shù)strlen,它包含于string.h中,因此我們需要在使用前添加頭文件 ,具體用法如下: strlen從數(shù)組頭部計數(shù),直到遇到字

    2024年02月06日
    瀏覽(23)
  • uni-app小程序引入iconfont的三種方式詳解(無需下載文件到項目)

    uni-app小程序引入iconfont的三種方式詳解(無需下載文件到項目)

    官網(wǎng)iconfont的引入方式有三種分別為: Unicode 、 Font class 、 Symbol , 其中已明確說明 Unicode、Font class 這兩種引入方式 不支持多色 。 單色如何理解吶?具體請看效果對比圖(左圖為UI上傳的圖標樣式,右邊為我們使用這兩種方式引入后不加任何樣式的效果) 是不是很丑? 另外

    2024年02月09日
    瀏覽(78)
  • 宏的使用(C語言詳解)

    宏的使用(C語言詳解)

    在寫一個代碼生成可執(zhí)行文件的過程需要經(jīng)過編譯和鏈接,編譯又要經(jīng)過三部:預處理,編譯,匯編。 #define定義的變量和宏就是在預處理階段會處理的。 一個簡單的宏定義: Max:宏名 a,b:宏參數(shù) ab?a:b:宏體 宏定義有些 類似函數(shù) ,Max(a,b)會被替換為 ab?a:b 比如這里printf

    2024年04月13日
    瀏覽(11)
  • 線程創(chuàng)建的三種方式

    線程創(chuàng)建的三種方式

    目錄 1.?Thread類 2.?Runnable接口 3. Callable接口 4. 線程的生命周期 新建? 就緒 運行 阻塞 等待 結束 繼承Thread類的方式創(chuàng)建線程 定義Thread類的子類,并重寫該類的run()方法,該run()方法的方法體就代表了線程需要完成的任務 創(chuàng)建Thread類的子類,即創(chuàng)建了線程對象 調用線程對象的

    2024年02月09日
    瀏覽(28)
  • selenium的三種等待方式

    設置固定休眠時間,單位為秒。 由python的time包提供, 導入 time 包后就可以使用。 缺點:不智能,使用太多的sleep會影響腳本運行速度。 使用方法:time.sleep(delay) 使用舉例:打開百度,強制等待5秒 (無條件等待,在一個時間段內等待) 一次設置,全局生效。 不要當作固定等待

    2023年04月13日
    瀏覽(14)
  • Debezium的三種部署方式

    Debezium的三種部署方式

    debezium 有下面三種部署方式,其中最常用的就是 kafka connect。 kafka connect 一般情況下,我們通過 kafka connect 來部署 debezium,kafka connect 是一個框架和運行時: source connectors:像 debezium 這樣將記錄發(fā)送到 kafka 的source connector sink connectors:將記錄從 kafka topic傳播到其他系統(tǒng)的 sin

    2024年02月10日
    瀏覽(22)
  • 解決NPE的三種方式

    解決NPE的三種方式

    NullPointerException(空指針異常,NPE)是Java編程中常見的錯誤。解決NPE的方法可以從以下三個方面考慮: 明確處理空引用情況: 在某些情況下,無法避免使用可能為空的引用對象。此時,需要明確處理空引用情況,以避免拋出NPE??梢允褂脳l件判斷,例如使用if-else語句或者三

    2024年02月22日
    瀏覽(31)
  • 驗證合約的三種方式

    使用truffle插件: https://github.com/rkalis/truffle-plugin-verify truffle run verify?合約名稱@合約地址?--network?網(wǎng)絡名稱 --debug 注意:需要開啟VPN,然后給CMD也設置代理,否則CMD無法訪問外網(wǎng)會驗證失敗 (每次新開CMD都要執(zhí)行) 在etherscan上手動上傳 1、合約文件如果有導入的外部合約,需

    2023年04月22日
    瀏覽(19)
  • redis的三種集群方式

    redis的三種集群方式

    redis有三種集群方式:主從復制,哨兵模式和集群。 ? ? 1.主從復制 ? 主從復制原理: ? 從服務器連接主服務器,發(fā)送SYNC命令;? 主服務器接收到SYNC命名后,開始執(zhí)行BGSAVE命令生成RDB文件并使用緩沖區(qū)記錄此后執(zhí)行的所有寫命令;? 主服務器BGSAVE執(zhí)行完后,向所有從服務器

    2024年02月13日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包