91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

函數宏的三種封裝方式

璟琰乀 ? 來源:大魚機器人 ? 作者:大魚機器人 ? 2020-12-22 15:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1. 函數宏介紹

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

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

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

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

因此,在工程中,一般使用三種方式來對函數宏進行封裝,分別為 {}、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ā)現編譯出錯:

。../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); 最后的 ; 已經把 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 的調用方式有違常理的,因為宏函數應該適用于任何語法。

優(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) 可以提前退出函數宏、整合為一條語句與強制調用時必須使用 ;。

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

#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) 方式的函數宏可以在無花括號且有分支的 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) 語法必須使用 ; 作為語句結尾。因此不可能存在以下語句的程序出現:

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

優(yōu)缺點總結:

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

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

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) 不同的是,({}) 不能提前退出函數宏與支持返回值。({}) 畢竟不是 while 循環(huán),不能直接使用 break退出函數宏是比較容易理解。那支持返回值是什么意思呢?

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

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

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

#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 宏已與函數十分接近。

優(yōu)缺點總結:

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

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

5. 總結綜上,在 {}、do{。..}while(0) 和 ({}) 這三種函數宏的封裝方式之中,應盡可能不使用 {},考慮兼容性一般選擇使用 do{。..}while(0),當需要函數宏返回時可以考慮使用 ({}) 或直接定義函數。

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 編程
    +關注

    關注

    90

    文章

    3716

    瀏覽量

    97166
  • 函數
    +關注

    關注

    3

    文章

    4417

    瀏覽量

    67494
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    C語言中實現函數三種方式

    的第一個分號后便結束。即 a = b 和 b = tmp 均不受控制語句所作用。 因此,在工程中,一般使用三種方式來對函數進行
    發(fā)表于 12-29 07:34

    請問CW32芯片的三種工作模式是什么?

    CW32芯片的三種工作模式是什么?
    發(fā)表于 12-26 06:48

    星海SK系列肖特基二極管SMBG、SMBX、SMC三種封裝選型建議

    本文將帶來星海SK系列肖特基二極管SMBG、SMBX、SMC三種封裝選型建議,幫助您為項目選擇最合適的器件。SMBG封裝尺寸適中:體積相對較小,適合在空間有限的P
    的頭像 發(fā)表于 10-16 16:08 ?1776次閱讀
    星海SK系列肖特基二極管SMBG、SMBX、SMC<b class='flag-5'>三種</b><b class='flag-5'>封裝</b>選型建議

    伺服電機的三種制動方式有什么區(qū)別?

    伺服電機作為自動化控制系統(tǒng)中執(zhí)行元件的核心部件,其制動性能直接影響設備的定位精度和安全可靠性。目前主流的伺服電機制動方式包括動態(tài)制動、再生制動和電磁機械制動三種,它們在制動原理、應用場景及技術特點上
    的頭像 發(fā)表于 09-19 18:26 ?1717次閱讀
    伺服電機的<b class='flag-5'>三種</b>制動<b class='flag-5'>方式</b>有什么區(qū)別?

    C語言中的內聯函數

    在C編程中,內聯函數都用于避免函數調用的開銷并編寫可復用的邏輯部分,但它們在工作方式和安全性方面存在顯著差異。
    的頭像 發(fā)表于 07-25 15:10 ?1900次閱讀
    C語言中的內聯<b class='flag-5'>函數</b>與<b class='flag-5'>宏</b>

    MEMS中的三種測溫方式

    在集成MEMS芯片的環(huán)境溫度測量領域,熱阻、熱電堆和PN結原理是三種主流技術。熱阻是利用熱敏電阻,如金屬鉑或注入硅的溫度電阻系數恒定,即電阻隨溫度線性變化的特性測溫,電阻變化直接對應絕對溫度,需恒流源供電。
    的頭像 發(fā)表于 07-16 13:58 ?1645次閱讀
    MEMS中的<b class='flag-5'>三種</b>測溫<b class='flag-5'>方式</b>

    1553B總線常見三種組網方式

    1553B總線作為航空電子系統(tǒng)中的關鍵通信協(xié)議,其組網方式直接影響系統(tǒng)的可靠性和實時性。本文將深入解析1553B總線的三種典型組網結構:單總線結構、雙冗余總線和多總線分層架構,并結合實際應用場景分析
    的頭像 發(fā)表于 06-21 17:39 ?1897次閱讀
    1553B總線常見<b class='flag-5'>三種</b>組網<b class='flag-5'>方式</b>

    開關電源三種控制模式:PWM/PFM/PSM

    摘要 本文詳細介紹了開關電源的三種主要調制方式:PWM(脈沖寬度調制)、PFM(脈沖頻率調制)和PSM(脈沖跨周期調制)。PWM通過調整脈沖寬度保持恒定頻率,適用于重負載,但輕負載效率低。PFM則在
    發(fā)表于 06-09 16:11

    介紹三種常見的MySQL高可用方案

    在生產環(huán)境中,為了確保數據庫系統(tǒng)的連續(xù)可用性、降低故障恢復時間以及實現業(yè)務的無縫切換,高可用(High Availability, HA)方案至關重要。本文將詳細介紹三種常見的 MySQL 高可用
    的頭像 發(fā)表于 05-28 17:16 ?1231次閱讀

    信號隔離器三種供電方式的區(qū)別

    信號隔離器是一重要的信號隔離裝置,其供電方式主要有獨立供電、回路供電和輸出回路供電三種。以下是這三種供電方式的詳細區(qū)別: 一、獨立供電 1
    的頭像 發(fā)表于 04-17 16:23 ?1525次閱讀
    信號隔離器<b class='flag-5'>三種</b>供電<b class='flag-5'>方式</b>的區(qū)別

    redis三種集群方案詳解

    在Redis中提供的集群方案總共有三種(一般一個redis節(jié)點不超過10G內存)。
    的頭像 發(fā)表于 03-31 10:46 ?1524次閱讀
    redis<b class='flag-5'>三種</b>集群方案詳解

    CMOS,Bipolar,FET這三種工藝的優(yōu)缺點是什么?

    在我用photodiode工具選型I/V放大電路的時候,系統(tǒng)給我推薦了AD8655用于I/V,此芯片為CMOS工藝 但是查閱資料很多都是用FET工藝的芯片,所以請教下用于光電信號放大轉換(主要考慮信噪比和帶寬)一般我們用哪種工藝的芯片, CMOS,Bipolar,FET這三種工藝的優(yōu)缺點是什么?
    發(fā)表于 03-25 06:23

    GaN、超級SI、SiC這三種MOS器件的用途區(qū)別

    如果想要說明白GaN、超級SI、SiC這三種MOS器件的用途區(qū)別,首先要做的是搞清楚這三種功率器件的特性,然后再根據材料特性分析具體應用。
    的頭像 發(fā)表于 03-14 18:05 ?2677次閱讀

    FOC中的三種電流采樣方式,你真的會選擇嗎?(可下載)

    的基礎,用一句話來形容就是“基礎不對,努力白費”,由此可見電流采樣在整 個 FOC 算法中的作用電流采樣的方式一般分為電阻、雙電阻、單電阻,這三種采樣方式都有其
    發(fā)表于 03-12 15:04 ?4次下載

    紅外探測器晶圓級、陶瓷級和金屬級三種封裝形式有什么區(qū)別?

    紅外探測器作為紅外熱像儀的核心部件,廣泛應用于工業(yè)、安防、醫(yī)療等多個領域。隨著技術的不斷進步,紅外探測器的封裝形式也在不斷發(fā)展和完善。其中,晶圓級、陶瓷級和金屬級封裝三種最常見的封裝
    的頭像 發(fā)表于 03-05 16:43 ?1309次閱讀
    紅外探測器晶圓級、陶瓷級和金屬級<b class='flag-5'>三種</b><b class='flag-5'>封裝</b>形式有什么區(qū)別?