亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語(yǔ)言進(jìn)階可變參數(shù)列表

 更新時(shí)間:2022年02月14日 14:39:33   作者:?jiǎn)虇碳业凝堼? 
這篇文章主要為大家介紹了C語(yǔ)言進(jìn)階可變參數(shù)列表的示例詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

可變參數(shù)

可變參數(shù)是C語(yǔ)言提供的一種參數(shù)可變的機(jī)制,咱希望函數(shù)帶有可變數(shù)量的參數(shù),而不是預(yù)定義數(shù)量的參數(shù)。它允許咱定義一個(gè)函數(shù),能根據(jù)具體的需求接受可變數(shù)量的參數(shù),比如這種:

int Max(int num,...)
{
 va_list arg;
 va_start(arg,num);
 int max = va_arg(arg,int);
 for(int i = 1;i<num;i++)
 {
 int sid = va_arg(arg,int);
 }
 if(sid > max)
 {
 max = sid;
 }
 va_end(arg);
 return max; 
}
int main()
{
int a = Max(5,1,2,3,4,5);
printf("%d\n",a);
return 0;
}

如上形式Max函數(shù)就用到了可變參數(shù),注意!使用可變參數(shù)時(shí),Max內(nèi)首元素 ‘ 5 ’代表元素個(gè)數(shù)

在這里插入圖片描述

那么問(wèn)題來(lái)了,如果函數(shù)沒(méi)有形式參數(shù),可以給函數(shù)傳遞嗎?答案是可以的,在C語(yǔ)言中,只要發(fā)生了函數(shù)調(diào)用并調(diào)用了參數(shù),必定會(huì)形成臨時(shí)變量;所謂臨時(shí)拷貝(變量)的本質(zhì),也就是在棧幀內(nèi)部形成的(從右向左形成臨時(shí)拷貝(變量)).

宏觀過(guò)程

va_list定義了可以訪問(wèn)可變參數(shù)部分的變量,他的本質(zhì)是一個(gè) char 類(lèi)型指針。va_start 使 b 指向可變參數(shù)部分,va_end 是用來(lái)完成收尾工作的,本質(zhì)就是將參數(shù)arg置為空,避免野指針。

掐頭去尾,我們看看主體部分。首先 arg 指針先讓我的數(shù)據(jù)入棧,我們打開(kāi)反匯編能看到棧頂 esp 位置,再在內(nèi)存窗口找到 esp 位置,就會(huì)看到這個(gè)經(jīng)典的一幕,倒著入棧連著幾個(gè)數(shù)據(jù)入棧是壓在一起的,這種結(jié)構(gòu)對(duì)我們查找元素就非常友好了。

在這里插入圖片描述


宏觀的框架就是我們傳入的變量 num 就代表第一個(gè)參數(shù) 5,va_start 就是讓 arg 原本指向5的 ,再讓他指向有效部分,比如 1,根據(jù)指向 1 的起始地址, va_start 指向他的可變部分(去掉已指向的有效部分),具體如何實(shí)現(xiàn)見(jiàn)下文;最后 va_arg 就是根據(jù)類(lèi)型 int ,從起始地址開(kāi)始連續(xù)讀取找到某一個(gè)元素,這樣最終會(huì)把所需要的 max 的值讀出來(lái)。

原理

可變參數(shù)列表對(duì)應(yīng)的函數(shù),最終調(diào)用也是函數(shù)調(diào)用,也要形成棧幀,棧幀形成前,臨時(shí)變量會(huì)先入棧,根據(jù)咱之前總結(jié)的,參數(shù)位置都是相對(duì)固定的;在可變參數(shù)中 ,如果是短整型,一般都要進(jìn)行整型提升,比如參數(shù)傳入的是 char 類(lèi)型,但實(shí)際傳出的是 int 類(lèi)型,這就是我們的 va_arg(arg,int)為什么是 int 而不是 char,所以在 va_arg 中指定了錯(cuò)誤的類(lèi)型,那結(jié)果無(wú)法預(yù)測(cè)。

要注意:
1.可變參數(shù)必須從頭到尾逐個(gè)進(jìn)行訪問(wèn),如果你訪問(wèn)了幾個(gè)可變參數(shù)后想半途而廢,是可以做到的,但如果一開(kāi)始就想訪問(wèn)中間某個(gè)元素的話,噠咩!
2.參數(shù)列表中至少有一個(gè)命名參數(shù),如果連一個(gè)參數(shù)都沒(méi)有,就沒(méi)辦法使用 va_start;
3.這些宏是沒(méi)辦法直接判斷實(shí)際存在的參數(shù)數(shù)量的,也無(wú)法判斷每個(gè)參數(shù)的類(lèi)型

格局打開(kāi)

#define _crt_va_start(ap,v)  (ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)
#define _crt_va_arg(ap,t)  (*(t*)((ap += _INTSIZEOF(t) - _INTSIZEOF(t))
#define _crt_va_start(ap)  (ap = (va_list)0)
)

談完原理就要談原理的原理,可變參數(shù)的幾個(gè)宏就給出了他的運(yùn)作原理,ap 就相當(dāng)于 arg, v 就相當(dāng)于變量 num,va_list 相當(dāng)于 char *,這里 ADDRESS 相當(dāng)于取地址,所以就是在對(duì) char 指針強(qiáng)轉(zhuǎn)之后,此時(shí)就有了一個(gè)指針以一字節(jié)為單位,指向入棧的第一個(gè)有效元素。要想繼續(xù)指向后面可變部分,就要繼續(xù)向下移動(dòng)四個(gè)字節(jié),加上他本身大小就能移動(dòng)到可變部分。

第二個(gè)宏也是特別有意思,ap是va_arg(arg,int),t 是我們的類(lèi)型—— int ,括號(hào)里的部分:(ap += _INTSIZEOF(t))其中 INTSIZEOF 計(jì)算了int 的大小,這里讓 ap 先 += 四個(gè)字節(jié),就讓 ap 直接指向了下一個(gè)元素的位置,后面再減去 int 的大小讓他又回到了第一個(gè)元素

在這里插入圖片描述


注意減的過(guò)程并沒(méi)有賦給 ap,ap指向的是 2,而整個(gè)表達(dá)式指向的是 4,(t) 將這個(gè) char 類(lèi)型指針強(qiáng)轉(zhuǎn)成 int 類(lèi)型指針再解引用,通過(guò)強(qiáng)制轉(zhuǎn)換,提取出符合類(lèi)型大小的數(shù)據(jù)。整個(gè)過(guò)程就是把第一個(gè)元素分離出來(lái)了。這個(gè)設(shè)計(jì)可謂非常優(yōu)秀,不僅指針下移了,元素也訪問(wèn)了,屬實(shí)美哉。

end宏很好理解,ap = 0了再?gòu)?qiáng)轉(zhuǎn)成 char* ,他的實(shí)際意義就是將指針歸0,避免野指針。

四字節(jié)對(duì)齊

INTSIZEOF 是如何實(shí)現(xiàn)的?我們將 INTSIZEOF 轉(zhuǎn)到定義,下面這段宏在函數(shù)內(nèi)部就開(kāi)始進(jìn)行使用了為什么還要進(jìn)行四字節(jié)對(duì)齊呢?因?yàn)閺氖自氐降诙€(gè)元素中間的空間是可以訪問(wèn)的,我不限制大小就有可能訪問(wèn)不到第二個(gè)元素,所以在形參被運(yùn)用時(shí)除了發(fā)生整型提升還有就是四字節(jié)對(duì)齊。

#define _INTSIZEOF(n)  ((sizeof(n) + sizeof(int) - 1)& ~(sizeof(int) - 1))

比如我是個(gè) char 類(lèi)型,sizeof(char)+sizeof(4)-1 &~ (sizeof(4)-1)就是 4 &~ 3,0000……0100 & 1111……1100 = 4 , 如此就能實(shí)現(xiàn)以最小的方式向上四字節(jié)取整,完成四字節(jié)對(duì)齊。從可讀性上講,這是真的麻煩,我們其實(shí)直接寫(xiě)成(n+4-1)& -(4-1)也無(wú)妨,這種簡(jiǎn)潔版不香嗎是吧。

今天就先到這里,摸了家人們,更多關(guān)于C語(yǔ)言可變參數(shù)列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++中封裝與信息隱藏的詳解及其作用介紹

    C++中封裝與信息隱藏的詳解及其作用介紹

    這篇文章主要介紹了C++中封裝與信息隱藏的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • C++動(dòng)態(tài)內(nèi)存分配超詳細(xì)講解

    C++動(dòng)態(tài)內(nèi)存分配超詳細(xì)講解

    給數(shù)組分配多大的空間?你是否和初學(xué)C時(shí)的我一樣,有過(guò)這樣的疑問(wèn)。這一期就來(lái)聊一聊動(dòng)態(tài)內(nèi)存的分配,讀完這篇文章,你可能對(duì)內(nèi)存的分配有一個(gè)更好的理解
    2022-08-08
  • C語(yǔ)言之格式化屏幕輸出詳解

    C語(yǔ)言之格式化屏幕輸出詳解

    這篇文章主要介紹了C語(yǔ)言之格式化屏幕輸出的相關(guān)資料,需要的朋友可以參考下,小編覺(jué)得這篇文章寫(xiě)的還不錯(cuò),希望能夠給你帶來(lái)幫助
    2021-11-11
  • C++11/14 線程中使用Lambda函數(shù)的方法

    C++11/14 線程中使用Lambda函數(shù)的方法

    這篇文章主要介紹了C++11/14 線程中使用Lambda函數(shù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • STL  priority_queue(優(yōu)先隊(duì)列)詳解

    STL priority_queue(優(yōu)先隊(duì)列)詳解

    這篇文章主要介紹了 STL priority_queue(優(yōu)先隊(duì)列)詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • QT實(shí)現(xiàn)用戶登錄注冊(cè)功能

    QT實(shí)現(xiàn)用戶登錄注冊(cè)功能

    這篇文章主要為大家詳細(xì)介紹了QT實(shí)現(xiàn)用戶登錄注冊(cè)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • vs2022?qt環(huán)境搭建調(diào)試的方法步驟

    vs2022?qt環(huán)境搭建調(diào)試的方法步驟

    最近net6和vs2022發(fā)布,本文就詳細(xì)的介紹一下vs2022?qt環(huán)境搭建調(diào)試的方法步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • C++?Boost?Conversion超詳細(xì)講解

    C++?Boost?Conversion超詳細(xì)講解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)
    2022-11-11
  • C++實(shí)現(xiàn)智能柜管理系統(tǒng)

    C++實(shí)現(xiàn)智能柜管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)智能柜管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++中int類(lèi)型按字節(jié)打印輸出的方法

    C++中int類(lèi)型按字節(jié)打印輸出的方法

    這篇文章主要給大家介紹了關(guān)于C++中int類(lèi)型按字節(jié)打印輸出的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05

最新評(píng)論