有專門的宏,處理可變參
我們提供的服務(wù)有:成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、越城ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的越城網(wǎng)站制作公司
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
一個(gè)簡(jiǎn)單的例子
void?simple_va_fun(int?i,?...)
{
va_list?arg_ptr;
int?j=0;
va_start(arg_ptr,?i);
j=va_arg(arg_ptr,?int);
va_end(arg_ptr);
printf("i=%d?j=%d\bn",?i,?j);
return;
}
int?main()
{
simple_va_fun(1);
simple_va_fun(1,2);
simple_va_fun(1,200);
return?0;
}
這是一個(gè)變參函數(shù)聲明。
加三個(gè)點(diǎn)就是了。
取得參數(shù)的套路是
這樣三步,就將 各個(gè)參數(shù),放在了 buf 中。
完整函數(shù)如下:
調(diào)用如下:
其中,vsprintf 可能造成內(nèi)存泄漏,因?yàn)閭魅氲?buf 的大小未知。
可換成
函數(shù)原型:
vsprintf 函數(shù)
vsnprintf 函數(shù)
在C/C++中,對(duì)函數(shù)參數(shù)的掃描是從后向前的。C/C++的函數(shù)參數(shù)是通過壓入堆棧的方式來給函數(shù)傳參數(shù)的(堆棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)),最先壓入的參數(shù)最后出來,在計(jì)算機(jī)的內(nèi)存中,數(shù)據(jù)有2塊,一塊是堆,一塊是棧(函數(shù)參數(shù)及局部變量在這里),而棧是從內(nèi)存的高地址向低地址生長(zhǎng)的,控制生長(zhǎng)的就是堆棧指針了,最先壓入的參數(shù)是在最上面,就是說在所有參數(shù)的最后面,最后壓入的參數(shù)在最下面,結(jié)構(gòu)上看起來是第一個(gè),所以最后壓入的參數(shù)總是能夠被函數(shù)找到,因?yàn)樗驮诙褩V羔樀纳戏健rintf的第一個(gè)被找到的參數(shù)就是那個(gè)字符指針,就是被雙引號(hào)括起來的那一部分,函數(shù)通過判斷字符串里控制參數(shù)的個(gè)數(shù)來判斷參數(shù)個(gè)數(shù)及數(shù)據(jù)類型,通過這些就可算出數(shù)據(jù)需要的堆棧指針的偏移量了,下面給出printf("%d,%d",a,b);(其中a、b都是int型的)的匯編代碼.
.section
.data
string out = "%d,%d"
push b //最后的先壓入棧中
push a //最先的后壓入棧中
push $out//參數(shù)控制的那個(gè)字符串常量是最后被壓入的
call printf
你會(huì)看到,參數(shù)是最后的先壓入棧中,最先的后壓入棧中,參數(shù)控制的那個(gè)字符串常量是最后被壓入的,所以這個(gè)常量總是能被找到的。
通常情況下函數(shù)可變參數(shù)表的長(zhǎng)度是已知的,通過num參數(shù)傳入,這種函數(shù)比較容易實(shí)現(xiàn)。
邊用邊學(xué)C語言視頻教程- 專輯- 視頻
邊用邊學(xué)C語言視頻教程--第一講 34:08; 播放: 316088 邊用邊學(xué)C語言視頻教程--第二講 42:55; 播放: 146905 邊用邊學(xué)C語言視頻教程--第三講 33:49; 播放: 79889
全國(guó)計(jì)算機(jī)等級(jí)考試二級(jí)(C語言)視頻教程- 視頻中心·易學(xué)院
全國(guó)計(jì)算機(jī)等級(jí)考試二級(jí)(C語言)視頻教程 C語言等級(jí)考試一直是廣大朋友比較頭痛的,c語言視頻教程針對(duì)此種情況21互聯(lián)特聘請(qǐng)了資深的老師,錄制了C語言等級(jí)考試課程,使廣大朋友
C語言程序設(shè)計(jì)入門視頻教程_編程開發(fā)_||電腦
2008年10月18日 C語言程序設(shè)計(jì)入門視頻教程主要包括:C語言概述;數(shù)據(jù)類型,運(yùn)算符和表達(dá)式;順序程序設(shè)計(jì)和選擇結(jié)構(gòu)程序設(shè)計(jì);循環(huán)控制;函數(shù)。
C語言程序設(shè)計(jì)視頻教程-eNet絡(luò)學(xué)院
C語言程序設(shè)計(jì)視頻教程 C語言程序設(shè)計(jì)作為大學(xué)理工課大一下學(xué)期必修的課程,c語言視頻教程也是本站(21shipin)所有其它編程語言的必學(xué)入門課程,學(xué)習(xí)該課程并不是要求大家能用C設(shè)計(jì)
c語言視頻教程
#include stdarg.h // 必須包含的頭文件
int Add(int start,...) // ...是作為占位符
{
va_list arg_ptr; // 定義變參起始指針
int sum=0; // 定義變參的和
int nArgValue =start; //
va_start(arg_ptr,start); // arg_ptr指向第一個(gè)變參
do
{
sum+=nArgValue; // 求和
nArgValue = va_arg(arg_ptr,int); // arg_ptr指向下一個(gè)變參
}
while(nArgValue != 0); // 判斷結(jié)束條件;結(jié)束條件是自定義為=0時(shí)結(jié)束
va_end(arg_ptr); // 復(fù)位指針
return sum;
}
函數(shù)的調(diào)用方法為Add(1,2,3,0);這樣,必須以0結(jié)尾,因?yàn)樽儏⒑瘮?shù)結(jié)束的判斷條件就是讀到0停止。
解釋:
所使用到的宏:
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
typedef char * va_list;
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
1、首先把va_list被定義成char*,這是因?yàn)樵谖覀兡壳八玫腜C機(jī)上,字符指針類型可以用來存儲(chǔ)內(nèi)存單元地址。而在有的機(jī)器上va_list是被定義成void*的
2、定義_INTSIZEOF(n)主要是為了某些需要內(nèi)存的對(duì)齊的系統(tǒng).這個(gè)宏的目的是為了得到最后一個(gè)固定參數(shù)的實(shí)際內(nèi)存大小。在我的機(jī)器上直接用sizeof運(yùn)算符來代替,對(duì)程序的運(yùn)行結(jié)構(gòu)也沒有影響。(后文將看到我自己的實(shí)現(xiàn))。
3、va_start的定義為 v+_INTSIZEOF(v) ,這里v是最后一個(gè)固定參數(shù)的起始地址,再加上其實(shí)際占用大小后,就得到了第一個(gè)可變參數(shù)的起始內(nèi)存地址。所以我們運(yùn)行va_start(ap, v)以后,ap指向第一個(gè)可變參數(shù)在的內(nèi)存地址,有了這個(gè)地址,以后的事情就簡(jiǎn)單了。
這里要知道兩個(gè)事情:
⑴在intel+windows的機(jī)器上,函數(shù)棧的方向是向下的,棧頂指針的內(nèi)存地址低于棧底指針,所以先進(jìn)棧的數(shù)據(jù)是存放在內(nèi)存的高地址處。
(2)在VC等絕大多數(shù)C編譯器中,默認(rèn)情況下,參數(shù)進(jìn)棧的順序是由右向左的,因此,參數(shù)進(jìn)棧以后的內(nèi)存模型如下圖所示:最后一個(gè)固定參數(shù)的地址位于第一個(gè)可變參數(shù)之下,并且是連續(xù)存儲(chǔ)的。
|--------------------------|
| 最后一個(gè)可變參數(shù) | -高內(nèi)存地址處
|--------------------------|
|--------------------------|
| 第N個(gè)可變參數(shù) | -va_arg(arg_ptr,int)后arg_ptr所指的地方,
| | 即第N個(gè)可變參數(shù)的地址。
|--------------- |
|--------------------------|
| 第一個(gè)可變參數(shù) | -va_start(arg_ptr,start)后arg_ptr所指的地方
| | 即第一個(gè)可變參數(shù)的地址
|--------------- |
|------------------------ --|
| |
| 最后一個(gè)固定參數(shù) | - start的起始地址
|-------------- -| .................
|-------------------------- |
| |
|--------------- | - 低內(nèi)存地址處
(4) va_arg():有了va_start的良好基礎(chǔ),我們?nèi)〉昧说谝粋€(gè)可變參數(shù)的地址,在va_arg()里的任務(wù)就是根據(jù)指定的參數(shù)類型取得本參數(shù)的值,并且把指針調(diào)到下一個(gè)參數(shù)的起始地址。
因此,現(xiàn)在再來看va_arg()的實(shí)現(xiàn)就應(yīng)該心中有數(shù)了:
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
這個(gè)宏做了兩個(gè)事情,
①用用戶輸入的類型名對(duì)參數(shù)地址進(jìn)行強(qiáng)制類型轉(zhuǎn)換,得到用戶所需要的值
②計(jì)算出本參數(shù)的實(shí)際大小,將指針調(diào)到本參數(shù)的結(jié)尾,也就是下一個(gè)參數(shù)的首地址,以便后續(xù)處理。
(5)va_end宏的解釋:x86平臺(tái)定義為ap=(char*)0;使ap不再 指向堆棧,而是跟NULL一樣.有些直接定義為((void*)0),這樣編譯器不會(huì)為va_end產(chǎn)生代碼,例如gcc在linux的x86平臺(tái)就是這樣定義的. 在這里大家要注意一個(gè)問題:由于參數(shù)的地址用于va_start宏,所以參數(shù)不能聲明為寄存器變量或作為函數(shù)或數(shù)組類型. 關(guān)于va_start, va_arg, va_end的描述就是這些了,我們要注意的 是不同的操作系統(tǒng)和硬件平臺(tái)的定義有些不同,但原理卻是相似的.
分享名稱:c語言變參函數(shù)視頻教程 c語言函數(shù)做形參
當(dāng)前地址:http://jinyejixie.com/article28/dosoocp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、移動(dòng)網(wǎng)站建設(shè)、App設(shè)計(jì)、全網(wǎng)營(yíng)銷推廣、網(wǎng)站維護(hù)、網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)