一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

3天內不再提示

函數(shù)宏的三種封裝方式

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

掃碼添加小助手

加入工程師交流群

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ù)。

責任編輯:haq

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

    關注

    88

    文章

    3689

    瀏覽量

    95274
  • 函數(shù)
    +關注

    關注

    3

    文章

    4381

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    MEMS中的三種測溫方式

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

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

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

    深入解析三種鋰電池封裝形狀背后的技術路線與工藝奧秘

    在新能源時代,鋰電池作為核心動力與儲能單元,其重要性不言而喻。而在鋰電池的諸多特性中,封裝形狀這一外在表現(xiàn)形式,實則蘊含著復雜的技術考量與工藝邏輯。方形、圓柱、軟包三種主流封裝形狀,各自對應著獨特
    的頭像 發(fā)表于 02-17 10:10 ?1199次閱讀
    深入解析<b class='flag-5'>三種</b>鋰電池<b class='flag-5'>封裝</b>形狀背后的技術路線與工藝奧秘

    三種太赫茲波的產(chǎn)生方式

    本文簡單介紹了三種太赫茲波的產(chǎn)生方式。 太赫茲波(THz)是一電磁波,在電磁波譜上位于紅外與微波之間。太赫茲光子能量在1-10 meV范圍之間,在光譜分析、醫(yī)療成像、移動通信方面都有非常廣闊
    的頭像 發(fā)表于 02-17 09:09 ?1851次閱讀
    <b class='flag-5'>三種</b>太赫茲波的產(chǎn)生<b class='flag-5'>方式</b>

    示波器的三種觸發(fā)模式

    示波器的觸發(fā)方式不僅影響波形捕捉的時機,還決定了顯示的波形是否穩(wěn)定。 常見的觸發(fā)模式有三種: 單次觸發(fā) (Single)、 正常觸發(fā) (Normal)和 自動觸發(fā) (Auto)。下面將對這三種觸發(fā)
    的頭像 發(fā)表于 01-07 11:04 ?7713次閱讀
    示波器的<b class='flag-5'>三種</b>觸發(fā)模式

    三種封裝形式下的400G光模塊概述

    本文主要就三種封裝形式(QSFP-DD、OSFP、QSFP112)的400G光模塊做了簡單的梳理,從為什么會有400G光模塊問世?400G光模塊在三種封裝形式下的各個具體型號(以短距離
    的頭像 發(fā)表于 11-11 11:35 ?1274次閱讀
    <b class='flag-5'>三種</b><b class='flag-5'>封裝</b>形式下的400G光模塊概述

    systemd journal收集日志的三種方式

    隨著 systemd 成了主流的 init 系統(tǒng),systemd 的功能也在不斷的增加,比如對系統(tǒng)日志的管理。Systemd 設計的日志系統(tǒng)好處多多,這里筆者就不再贅述了,本文筆者主要介紹 systemd journal 收集日志的三種方式
    的頭像 發(fā)表于 10-23 11:50 ?827次閱讀
    systemd journal收集日志的<b class='flag-5'>三種</b><b class='flag-5'>方式</b>

    I2S有左對齊,右對齊跟標準的I2S三種格式,那么這三種格式各有什么優(yōu)點呢?

    大家好,關于I2S格式,有兩個疑問請教一下 我們知道I2S有左對齊,右對齊跟標準的I2S三種格式,那么這三種格式各有什么優(yōu)點呢? 而且對于標準的I2S格式,32FS傳輸16bit的數(shù)據(jù),48fs傳輸24bit的數(shù)據(jù),最低位會移動到右聲道,是否意味著該數(shù)據(jù)被丟棄了?還是有
    發(fā)表于 10-21 08:23

    Windows管理內存的三種主要方式

    Windows操作系統(tǒng)提供了多種方式來管理內存,以確保系統(tǒng)資源的有效利用和性能的優(yōu)化。以下是關于Windows管理內存的三種主要方式的詳細闡述,包括堆內存管理、虛擬內存管理以及共享內存管理,每種
    的頭像 發(fā)表于 10-12 17:09 ?2392次閱讀

    如何利用三種 SOT-563 封裝實現(xiàn)共同布局

    電子發(fā)燒友網(wǎng)站提供《如何利用三種 SOT-563 封裝實現(xiàn)共同布局.pdf》資料免費下載
    發(fā)表于 09-10 14:25 ?0次下載
    如何利用<b class='flag-5'>三種</b> SOT-563 <b class='flag-5'>封裝</b>實現(xiàn)共同布局

    shell腳本執(zhí)行的三種方式及區(qū)別

    在Linux系統(tǒng)中,Shell腳本是一非常實用的工具,用于自動化執(zhí)行一系列命令。Shell腳本可以大大提高工作效率,簡化復雜的任務。在這篇文章中,我們將介紹Shell腳本執(zhí)行的三種方式及其區(qū)別
    的頭像 發(fā)表于 08-30 15:24 ?2221次閱讀

    簡述三種esp32的開發(fā)方式是什么

    ESP32是一款由樂鑫(Espressif)推出的低功耗、高性能的Wi-Fi和藍牙雙模無線通信芯片,廣泛應用于物聯(lián)網(wǎng)、智能家居、智能硬件等領域。本文將詳細介紹三種ESP32的開發(fā)方式:Arduino
    的頭像 發(fā)表于 08-20 09:11 ?8091次閱讀

    常用的pwm跟蹤控制方式是哪三種

    PWM(脈寬調制)跟蹤控制是一廣泛應用于電機控制、電源管理、通信等領域的技術。它通過調整脈沖的寬度來控制輸出信號的占空比,從而實現(xiàn)對系統(tǒng)的精確控制。常用的PWM跟蹤控制方式主要有三種:增量式PWM
    的頭像 發(fā)表于 08-14 10:34 ?2604次閱讀

    計算機網(wǎng)絡中的三種通信方式

    計算機網(wǎng)絡中的三種通信方式,即單工通信、半雙工通信和全雙工通信,是理解和設計高效網(wǎng)絡架構的基礎。每種通信方式都有其獨特的特性、應用場景及優(yōu)缺點。以下是對這三種通信
    的頭像 發(fā)表于 08-07 15:00 ?5162次閱讀

    逆變電路的三種調壓方式

    路的三種調壓方式:脈寬調制(PWM)調壓、相位控制調壓和頻率調制調壓。 1. 脈寬調制(PWM)調壓 脈寬調制是一通過改變脈沖寬度來調整輸出電壓的調壓方式。在PWM調壓中,逆變電路的
    的頭像 發(fā)表于 08-02 16:59 ?4406次閱讀