第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

求助關(guān)于C語(yǔ)言的變參技術(shù),va_start,va_arg,va_end這幾個(gè)函數(shù)怎么用?

求助關(guān)于C語(yǔ)言的變參技術(shù),va_start,va_arg,va_end這幾個(gè)函數(shù)怎么用?

C PHP
縹緲止盈 2022-03-11 09:05:43
誰(shuí)能給解釋一下va_start,va_arg,va_end這幾個(gè)函數(shù)怎么用,越庸俗越好。推薦幾篇文章也非常感謝?。?!
查看完整描述

1 回答

?
婷婷同學(xué)_

TA貢獻(xiàn)1844條經(jīng)驗(yàn) 獲得超8個(gè)贊

#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ī)上,字符指針類型可以用來(lái)存儲(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)算符來(lái)代替,對(duì)程序的運(yùn)行結(jié)構(gòu)也沒(méi)有影響。(后文將看到我自己的實(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)在再來(lái)看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è)問(wèn)題:由于參數(shù)的地址用于va_start宏,所以參數(shù)不能聲明為寄存器變量或作為函數(shù)或數(shù)組類型. 關(guān)于va_start, va_arg, va_end的描述就是這些了,我們要注意的 是不同的操作系統(tǒng)和硬件平臺(tái)的定義有些不同,但原理卻是相似的.



查看完整回答
反對(duì) 回復(fù) 2022-03-15
  • 1 回答
  • 0 關(guān)注
  • 158 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)