可變引數列表解析及簡單應用

2022-09-23 12:33:08 字數 2365 閱讀 8613

可變引數列表解析及簡單應用:在函式原型中,列出函式期望接受的引數,但是原型只能顯示固定數目的引數。通俗來講就是,當我們給定函式原型時候,我們也就確定了函式的引數的個數,傳遞引數的時候必須按照原型提供的引數個數來傳遞引數。

那麼我們是否可以傳遞引數時候,提供可變個引數呢?

當然是可以的,比如我們常用的printf()函式,我們可以用以下方式傳遞多個引數給此函式。

printf("hello");//乙個引數

printf("%d",12);//兩個引數

printf("%d%d",12,11);//三個引數

在msdn幫助文件中檢視printf()函式的原型可以看到:

可以看到在printf函式引數中有由 「…」組成的引數構成,這是可變函式引數的標準格式,也是標誌。我們把引數可變的函式叫做可變引數函式。

可變引數列表是通過巨集來實現的,這些巨集定義在標頭檔案stdarg.h中,這個標頭檔案中宣告了乙個型別va_lsit和三個巨集——va_start、va_arg、va_end。

解析:va_list型別:這個型別是通過typedef將char 型別進行了重新命名,也就是說va_list是char 型別。

va_start巨集:用來初始化,它的第乙個引數是va_list變數的名字,第二個引數是省略號前最後乙個用名字的引數。初始化過程是把va_list型別的變數設定為指向可變引數部分的第乙個引數。

va_arg巨集:為了訪問引數,需要使用這個巨集來實現,這個巨集接受兩個引數,va_list變數和下乙個引數的型別。

va_end巨集:使用這個巨集來結束訪問。

以下是簡單實現用可變引數列表來求不同個數引數的平均值。

/***1*/

#include

#include

#include

float **erage(int num, ...)

va_end(arg);//呼叫結束

return sum / num;

}int main()

那麼可變引數列表是如何實現的呢?原理是什麼呢?我們進入原始碼檢視

typedef char * va_list;

#define va_start _crt_va_start;

#define va_arg _crt_va_arg;

#define va_end _crt_va_end;

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

#define _addressof(v) ( &(v) )

#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_end(ap) ( ap = (va_list)0 )

可以看到va_list型別實質是char *型別。

而va_start、va_arg、va_end經過巨集定義為_crt_va_start、_crt_va_arg、_crt_va_end.

為什麼要定義為_crt函式呢?首先我們得了解什麼是crt函式,一般來說,crt函式就是標準的c語言函式。而可變引數列表是標準庫的一部分。

為了對巨集定義進行分析說明,我們將巨集定義全部替換可得到如下:

先來解釋此處的巨集定義的作用:

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

_intsizeof(n)整個做的事情就是將n的長度化為int長度的整數倍。

比如n為5,二進位制就是101b,int長度為4,二進位制為100b,那麼n化為int長度的整數倍就應該為8。

~(sizeof(int) - 1) )就應該為~(4-1)=~(00000011b)=11111100b,這樣任何數& ~(sizeof(int) - 1) )後最後兩位肯定為0,就肯定是4的整數倍了。

(sizeof(n) + sizeof(int) - 1)就是將大於4m但小於等於4(m+1)的數提高到大於等於4(m+1)但小於4(m+2),這樣再& ~(sizeof(int) - 1) )後就正好將原長度補齊到4的倍數了。

(通俗的說,就是當n為1,2,3,4的時候n取值為4. n位5,6,7,8的時候n值取值為8.依次類推)

我們用**1進行例項分析

float **erage(int num, ...)

arg=((char *)0);

return sum / num;

}int main()

進行棧幀分析來分析呼叫原理

可變引數列表解析

c語言中的可變引數是乙個比較有意思的實現,通過將函式實現為可變引數的形式,可以使得函式可以接受1個以上的任意多個引數 不固定 看乙個例子,求取幾個數裡面的最大值。主要 如下 int max int n,va end arg,int return max 關鍵問題是搞懂va list,va start...

可變引數列表解析

在c語言中 有些函式我們無法確定其需要傳遞的引數的個數 可以用省略號指定引數。它是利用函式傳參時的過程實現的,函式傳參過程是以棧的形式訪問的。關於函式棧幀 通過下面的 來演示 include include int add int n,n為後面引數的個數,為可選引數 int main 執行結果 在v...

可變引數列表解析

1 printf d n 2018 2 printf s n hello world 3 printf d s n 2018,i m fine.int printf const char format,1 va list arg 2 void va start va list arg ptr,pre...