最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C語(yǔ)言可變參數(shù)(從stdarg.h到應(yīng)用)

2022-11-27 18:32 作者:AaaGss  | 我要投稿

1. 什么是可變參數(shù)函數(shù)

在C語(yǔ)言編程中有時(shí)會(huì)遇到一些參數(shù)可變的函數(shù),例如printf()、scanf(),其函數(shù)原型為:

就拿 printf 來(lái)說(shuō)吧,它除了有一個(gè)參數(shù) format 固定以外,后面的參數(shù)其個(gè)數(shù)和類(lèi)型都是可變的,用三個(gè)點(diǎn)“…”作為參數(shù)占位符。

2. 參數(shù)列表的構(gòu)成

任何一個(gè)可變參數(shù)的函數(shù)都可以分為兩部分:固定參數(shù)和可選參數(shù)。至少要有一個(gè)固定參數(shù),其聲明與普通函數(shù)參數(shù)聲明相同;可選參數(shù)由于數(shù)目不定(0個(gè)或以上),聲明時(shí)用"…"表示。固定參數(shù)和可選參數(shù)共同構(gòu)成可變參數(shù)函數(shù)的參數(shù)列表。

3. 實(shí)現(xiàn)原理

C語(yǔ)言中使用?va_list?系列變參宏實(shí)現(xiàn)變參函數(shù),此處va意為variable-argument(可變參數(shù))。

x86平臺(tái)VC6.0編譯器中,stdarg.h頭文件內(nèi)變參宏定義如下:


_INTSIZEOF(n)

_INTSIZEOF宏考慮到某些系統(tǒng)需要內(nèi)存地址對(duì)齊。從宏名看應(yīng)按照sizeof(int)即棧粒度對(duì)齊,參數(shù)在內(nèi)存中的地址均為sizeof(int)=4的倍數(shù)。

例如,若1≤sizeof(n)≤4,則_INTSIZEOF(n)=4;若5≤sizeof(n)≤8,則_INTSIZEOF(n)=8。

在不考慮內(nèi)存的情況下,庫(kù)函數(shù)中的這條語(yǔ)句?(sizeof(n)+ sizeof(int) - 1) & ~(sizeof(int)-1)背后的意義也可以當(dāng)作一種映射算法。具體上代碼:

f%5Cleft(%20x%20%5Cright)%20%3D%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bl%7D%0A%092%5C%2C%5C%2C%2C1%5Cle%20x%5Cle%202%5C%5C%0A%094%5C%2C%5C%2C%2C3%5Cle%20x%5Cle%204%5C%5C%0A%09%5Ccdots%5C%5C%0A%5Cend%7Barray%7D%20%5Cright.%20%5C%20%5C%20%2C%5C%20x%5Cin%20%5Ctext%7BN%7D%5E%2B


f%5Cleft(%20x%20%5Cright)%20%3D%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bl%7D%0A%094%5C%20%2C1%5Cle%20x%5Cle%204%5C%5C%0A%098%5C%20%2C5%5Cle%20x%5Cle%208%5C%5C%0A%09%5Ccdots%5C%5C%0A%5Cend%7Barray%7D%20%5Cright.%20%20%5C%20%5C%20%2C%5C%20x%5Cin%20%5Ctext%7BN%7D%5E%2B


相信大家都看出規(guī)律了,這里就不總結(jié)了。另外int num,int mask是有符號(hào)的,當(dāng)形參num為負(fù)數(shù)的時(shí)候,或者形參mask為負(fù)數(shù)的時(shí)候,這樣就還有三種情況,有的也是有規(guī)律的,這里就不贅述了。


va_start(ap,v)

va_start宏首先根據(jù)(va_list)&v得到參數(shù) v 在棧中的內(nèi)存地址,加上_INTSIZEOF(v)即v所占內(nèi)存大小后,使 ap 指向 v 的下一個(gè)參數(shù)。在使用的時(shí)候,一般用這個(gè)宏初始化 ap 指針,v 是變參列表的前一個(gè)參數(shù),即最后一個(gè)固定參數(shù),初始化的結(jié)果是 ap 指向第一個(gè)變參。

va_arg(ap, type)

這個(gè)宏取得 type 類(lèi)型的可變參數(shù)值。首先ap += _INTSIZEOF(type),即 ap 跳過(guò)當(dāng)前可變參數(shù)而指向下個(gè)變參的地址;然后ap-_INTSIZEOF(type)得到當(dāng)前變參的內(nèi)存地址,類(lèi)型轉(zhuǎn)換后解引用,最后返回當(dāng)前變參值。

va_end(ap)

va_end 宏使 ap 不再指向有效的內(nèi)存地址。該宏的某些實(shí)現(xiàn)定義為((void*)0),編譯時(shí)不會(huì)為其產(chǎn)生代碼,調(diào)用與否并無(wú)區(qū)別。但某些實(shí)現(xiàn)中 va_end 宏用于在函數(shù)返回前完成一些必要的清理工作:如 va_start 宏可能以某種方式修改棧,導(dǎo)致返回操作無(wú)法完成,va_end 宏可將有關(guān)修改復(fù)原;又如 va_start 宏可能為參數(shù)列表動(dòng)態(tài)分配內(nèi)存以便于遍歷,va_end 宏可釋放此內(nèi)存。因此,從使用 va_start 宏的函數(shù)中退出之前,必須調(diào)用一次 va_end 宏。


4. 代碼示例

變參宏無(wú)法智能識(shí)別可變參數(shù)的數(shù)目和類(lèi)型,因此實(shí)現(xiàn)變參函數(shù)時(shí)需自行判斷可變參數(shù)的數(shù)目和類(lèi)型。所以我們就要想一些辦法,比如

  1. 顯式提供變參數(shù)目或設(shè)定遍歷結(jié)束條件

  2. 顯式提供變參類(lèi)型枚舉值,或在固定參數(shù)中包含足夠的類(lèi)型信息(如printf函數(shù)通過(guò)分析format字符串即可確定各變參類(lèi)型)

  3. 主調(diào)函數(shù)和被調(diào)函數(shù)可約定變參的數(shù)目和類(lèi)型

例1:函數(shù)通過(guò)固定參數(shù)指定可變參數(shù)個(gè)數(shù),打印所有變參值

例2:函數(shù)定義一個(gè)結(jié)束標(biāo)記(-1),調(diào)用時(shí)通過(guò)最后一個(gè)參數(shù)傳遞該標(biāo)記,打印標(biāo)記前所有變參值。

需要注意

va_arg(ap, type)宏中的 type 不可指定為以下類(lèi)型:

  • char

  • short

  • float

在C語(yǔ)言中,調(diào)用不帶原型聲明或聲明為變參的函數(shù)時(shí),主調(diào)函數(shù)會(huì)在傳遞未顯式聲明的參數(shù)前對(duì)其執(zhí)行缺省參數(shù)提升(default argument promotions),將提升后的參數(shù)值傳遞給被調(diào)函數(shù)。

提升操作如下:

  • float 類(lèi)型的參數(shù)提升為 double 類(lèi)型

  • char、short 和相應(yīng)的 signed、unsigned 類(lèi)型參數(shù)提升為 int 類(lèi)型

  • 若 int 類(lèi)型不能容納原值,則提升為 unsigned int 類(lèi)型

最后來(lái)一張圖,幫助大家理解前文講的宏。

5. 應(yīng)用

在嵌入式開(kāi)發(fā)中,經(jīng)常使用int fputc(int ch, FILE *f)重映射printf()函數(shù),例如重映射到ITM、串口、oled屏幕等,這種方式只能映射到一個(gè)地方,不是很方便。下面介紹一個(gè)終極方法,實(shí)現(xiàn)可變參數(shù)任意端口打印。這里以oled為例,代碼如下:

6. 參考資料

https://blog.csdn.net/longintchar/article/details/85490103

https://www.cnblogs.com/clover-toeic/p/3736748.html


C語(yǔ)言可變參數(shù)(從stdarg.h到應(yīng)用)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
花垣县| 南召县| 禹城市| 临泽县| 三河市| 平顶山市| 隆回县| 临泽县| 玉门市| 龙岩市| 察哈| 三原县| 井陉县| 东山县| 福海县| 吉木萨尔县| 鄱阳县| 上林县| 周宁县| 襄樊市| 舒城县| 江陵县| 新民市| 柞水县| 安化县| 嘉定区| 启东市| 墨玉县| 开平市| 马龙县| 东宁县| 内丘县| 渝中区| 松阳县| 滁州市| 宁晋县| 汉川市| 前郭尔| 如皋市| 杭州市| 唐海县|