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

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言可變參數(shù)的使用詳解

硬件攻城獅 ? 來源:硬件攻城獅 ? 2023-03-08 09:47 ? 次閱讀

一、可變參數(shù)表介紹

c/c++語言具備一個(gè)不同于其他編程語言的的特性,即支持可變參數(shù)。

例如C庫中的printf,scanf等函數(shù),都支持輸入數(shù)量不定的參數(shù)。例如:

printf("helloworld");////

printf函數(shù)原型為 int printf(const char *format, …);

從printf的原型來看,其除了接受一個(gè)固定參數(shù)format以外,后面的參數(shù)使用來表示。

在c/c++語言中,表示可以接受不定數(shù)量的參數(shù)。

二、可變參數(shù)表用法

在標(biāo)準(zhǔn)C/C++中,頭文件中定義了如下三個(gè)宏:

voidva_start(va_listarg_ptr,prev_param);/*ANSIversion*/
typeva_arg(va_listarg_ptr,type);
voidva_end(va_listarg_ptr);

va 就是variable argument(可變參數(shù))的意思

arg_ptr 是指向可變參數(shù)表的指針

prev_param 則指可變參數(shù)表的前一個(gè)固定參數(shù)

type 為可變參數(shù)的類型

va_list 也是一個(gè)宏

其定義為typedef char * va_list 實(shí)質(zhì)上是一char 型指針。
char 型指針的特點(diǎn)是++、--操作對其作用的結(jié)果是增1 和減1(因?yàn)閟izeof(char)為1)。
與之不同的是int 等其它類型指針的++、--操作對其作用的結(jié)果是增sizeof(type)或減sizeof(type),而且sizeof(type)大于1。

通過使用va_start宏我們可以取得可變參數(shù)表的首指針,這個(gè)宏的定義為:

#defineva_start(ap,v)(ap=(va_list)&v+_INTSIZEOF(v))

其作用為將最后那個(gè)固定參數(shù)的地址加上可變參數(shù)對其的偏移后賦值給ap,這樣ap就是可變參數(shù)表的首地址。

_INTSIZEOF 宏定義為:

#define_INTSIZEOF(n)((sizeof(n)+sizeof(int)–1)&~(sizeof(int)–1))

宏定義va_arg原型為:

#defineva_arg(list,mode)((mode*)(list=
(char*)((((int)list+(__builtin_alignof(mode)<=4?3:7))?&
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

其作用為指取出當(dāng)前arg_ptr 所指的可變參數(shù)并將ap 指針指向下一可變參數(shù)。

va_end宏定義用來結(jié)束可變參數(shù)的獲取,定義為:

#defineva_end(list)

va_end ( list )實(shí)際上被定義為空,沒有任何真實(shí)對應(yīng)的代碼,用于代碼對稱,與va_start對應(yīng);

可能發(fā)揮代碼的“自注釋”作用。所謂代碼的“自注釋”,指的是代碼能自己注釋自己。

三、可變參數(shù)表的簡單使用

#include
#include
#include

/**
*@brief求n個(gè)數(shù)中的最大值
*@details
*@param[in]num整數(shù)個(gè)數(shù)
*@param[out]...整數(shù)
*@retval最大整數(shù)
*@par
*/
intmax(intnum,...){
intm=-0x7FFFFFFF;/*32系統(tǒng)中最小的整數(shù)*/
va_listap;
va_start(ap,num);
for(inti=0;im){
m=t;
}
}
va_end(ap);
returnm;
}

intmain(intargc,char*argv[]){
intn=max(5,5,6,3,8,5);/*求5個(gè)整數(shù)中的最大值*/
cout<

max(int num, …)中首先定義了可變參數(shù)表指針ap,而后通過va_start ( ap, num )取得了參數(shù)表首地址(賦給了ap),其后的for 循環(huán)則用來遍歷可變參數(shù)表。

max函數(shù)相比于printf簡單了許多,其原因如下:

max函數(shù)可變參數(shù)表的長度是已知的,通過num參數(shù)傳入;

max函數(shù)可變參數(shù)表中參數(shù)的類型是已知的,都為int型;

printf 函數(shù)可變參數(shù)的個(gè)數(shù)不能輕易的得到,而可變參數(shù)的類 型也不是固定的,需由格式字符串進(jìn)行識別(由%f、%d、%s 等確定)。

四、運(yùn)行機(jī)制

匯編是研究語法深層特性的終極良策,首先查看main函數(shù)中調(diào)用max函數(shù)時(shí)的反匯編:

1.004010C8push5
2.004010CApush8
3.004010CCpush3
4.004010CEpush6
5.004010D0push5
6.004010D2push5
7.004010D4call@ILT+5(max)(0040100a)

第一步:將參數(shù)從右向左入棧(第1~6行)

第二步:調(diào)用call 指令進(jìn)行跳轉(zhuǎn)(第7行)

這兩步包含了深刻的含義,它說明C/C++默認(rèn)的調(diào)用方式為由調(diào)用者管理參數(shù)入棧的操作,且入棧的順序?yàn)閺挠抑磷螅@種調(diào)用方式稱為_cdecl調(diào)用。

x86系統(tǒng)的入棧方向?yàn)閺母叩刂返降偷刂?,故?至n個(gè)參數(shù)被放在了地址遞增的堆棧內(nèi)。在被調(diào)用函數(shù)內(nèi)部,讀取這些堆棧的內(nèi)容就可獲得各個(gè)參數(shù)的值,讓我們反匯編到max函數(shù)的內(nèi)部。

intmax(intnum,...){
1.00401020pushebp
2.00401021movebp,esp
3.00401023subesp,50h
4.00401026pushebx
5.00401027pushesi
6.00401028pushedi
7.00401029leaedi,[ebp-50h]
8.0040102Cmovecx,14h
9.00401031moveax,0CCCCCCCCh
10.00401036repstosdwordptr[edi]
va_listap;
intm=-0x7FFFFFFF;/*32系統(tǒng)中最小的整數(shù)*/
11.00401038movdwordptr[ebp-8],80000001h
va_start(ap,num);
12.0040103Fleaeax,[ebp+0Ch]
13.00401042movdwordptr[ebp-4],eax
for(inti=0;im)
28.00401071moveax,dwordptr[t]
29.00401074cmpeax,dwordptr[ebp-8]
30.00401077jlemax+5Fh(0040107f)
m=t;
31.00401079movecx,dwordptr[t]
32.0040107Cmovdwordptr[ebp-8],ecx
}
33.0040107Fjmpmax+2Eh(0040104e)
va_end(ap);
34.00401081movdwordptr[ebp-4],0
returnm;
35.00401088moveax,dwordptr[ebp-8]
}
36.0040108Bpopedi
37.0040108Cpopesi
38.0040108Dpopebx
39.0040108Emovesp,ebp
40.00401090popebp
41.00401091ret

第1~10行進(jìn)行執(zhí)行函數(shù)內(nèi)代碼的準(zhǔn)備工作,保存現(xiàn)場;

第2行對堆棧進(jìn)行移動(dòng);

第3行則意味著max函數(shù)為其內(nèi)部局部變量準(zhǔn)備的堆??臻g為50h字節(jié);

第11行表示把變量n 的內(nèi)存空間安排在了函數(shù)內(nèi)部局部棧底減8的位置(占用4個(gè)字節(jié));

第12~13行非常關(guān)鍵,對應(yīng)著va_start ( ap, num),這兩行將第一個(gè)可變參數(shù)的地址賦值給了指針ap;

從第12行可以看出num 的地址為ebp+0Ch;

從第13行可以看出ap 被分配在函數(shù)內(nèi)部局部棧底減4 的位置上(占用4 個(gè)字節(jié));

第22~27行最為關(guān)鍵,對應(yīng)著va_arg (ap, int);

第22~24行的作用為將ap 指向下一可變參數(shù)(可變參數(shù)的地址間隔為4 個(gè)字節(jié),從add eax,4 可以看出);

第25~27行則取當(dāng)前可變參數(shù)的值賦給變量t。這段反匯編很奇怪,它先移動(dòng)可變參數(shù)指針,再在賦值指令里面回過頭來取先前的參數(shù)值賦給t(從mov edx,dword ptr [ecx-4]語句可以看出);

第36~41行恢復(fù)現(xiàn)場和堆棧地址,執(zhí)行函數(shù)返回操作。

審核編輯:湯梓紅

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

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135585
  • 編程語言
    +關(guān)注

    關(guān)注

    10

    文章

    1921

    瀏覽量

    34505
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4260

    瀏覽量

    62231
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2090

    瀏覽量

    73405
  • 可變參數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    4810

原文標(biāo)題:C語言可變參數(shù)的使用詳解

文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C語言可變形參是什么

    ??C語言允許定義參數(shù)數(shù)量可變的函數(shù),這稱為可變參數(shù)函數(shù)(variadic function)。
    的頭像 發(fā)表于 08-18 21:40 ?1264次閱讀

    可變參數(shù)函數(shù)的實(shí)現(xiàn)原理

    ,或者其它方式。在C語言標(biāo)準(zhǔn)頭文件stdarg.h里面已經(jīng)為可變函數(shù)定義了幾個(gè)宏,使用這些宏也可以實(shí)現(xiàn)可變參數(shù)函數(shù),原理都一樣, 細(xì)節(jié)不再介
    發(fā)表于 10-21 22:18

    C語言內(nèi)存管理詳解

    C語言內(nèi)存管理詳解,很不錯(cuò)的一份資料.
    發(fā)表于 08-06 23:14

    C語言——可變參數(shù)問題.

    ;The value is %d!\n", value);  這種可變參數(shù)可以說是C語言一個(gè)比較難理解的部分,這里會(huì)由幾個(gè)問題引發(fā)一些對它的分析。   注意:在
    發(fā)表于 04-20 15:17

    C語言可變參數(shù)的定義

    C語言可變參數(shù)的定義。//可變參數(shù)用...來表示void TRACE(char *forma
    發(fā)表于 07-14 07:43

    怎么設(shè)計(jì)c語言可變參數(shù)函數(shù)?

    怎么設(shè)計(jì)c語言可變參數(shù)函數(shù)
    發(fā)表于 10-27 07:10

    C++ 語言命令詳解(第二版)

    電子發(fā)燒友網(wǎng)站提供《C++ 語言命令詳解(第二版).txt》資料免費(fèi)下載
    發(fā)表于 07-28 13:06 ?0次下載

    C語言詳解_ifdef等宏及妙用

    C語言詳解_ifdef等宏及妙用的教程
    發(fā)表于 11-16 19:03 ?0次下載

    徹底搞定C語言指針詳解完整版

    徹底搞定C語言指針詳解完整版。
    發(fā)表于 05-10 17:04 ?0次下載

    ARM_C語言程序設(shè)計(jì)詳解

    ARM_C語言程序設(shè)計(jì)詳解
    發(fā)表于 10-27 15:39 ?32次下載
    ARM_<b class='flag-5'>C</b><b class='flag-5'>語言</b>程序設(shè)計(jì)<b class='flag-5'>詳解</b>

    C語言的精髓——指針詳解

    C語言的精髓——指針詳解
    發(fā)表于 11-30 14:43 ?17次下載

    單片機(jī)C語言和匯編語言混合編程實(shí)例詳解

    單片機(jī)C語言和匯編語言混合編程實(shí)例詳解
    發(fā)表于 08-16 09:50 ?225次下載

    C語言-函數(shù)的可變形參(不定形參)

    這篇文章介紹C語言函數(shù)的不定參數(shù)、可變參數(shù) 形參,實(shí)現(xiàn)printf一樣的傳參效果。
    的頭像 發(fā)表于 08-14 09:58 ?2494次閱讀

    c語言參數(shù)的宏定義

    c語言參數(shù)的宏定義? C語言宏定義是一種宏替換機(jī)制,它可以將一個(gè)標(biāo)識符替換為一個(gè)代碼片段。宏定義通常在程序中用來方便地進(jìn)行常量定義或函數(shù)模
    的頭像 發(fā)表于 09-04 17:45 ?2291次閱讀

    C語言中的可變參數(shù)介紹

    C 語言為這種情況提供了一個(gè)解決方案,它允許您定義一個(gè)函數(shù),能根據(jù)具體的需求接受可變數(shù)量的參數(shù)
    發(fā)表于 02-28 14:00 ?252次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>中的<b class='flag-5'>可變</b><b class='flag-5'>參數(shù)</b>介紹