c/c++語言有乙個不同於其它語言的特性,即其支援可變引數,典型的函式如printf、scanf等可以接受數量不定的引數。如:
printf ( "i love you" );
printf ( "%d", a );
printf ( "%d,%d", a, b );
第一、二、三個printf分別接受1、2、3個引數,讓我們看看printf函式的原型:
int printf ( const char *format, ... );
從函式原型可以看出,其除了接收乙個固定的引數format以外,後面的引數用"…"表示。在c/c++語言中,"…"表示可以接受不定數量的引數,理論上來講,可以是0或0以上的n個引數。
本文將對c/c++可變參數列的使用方法及c/c++支援可變參數列的深層機理進行探索。
可變參數列的用法
1、相關巨集
標準c/c++包含標頭檔案stdarg.h,該標頭檔案中定義了如下三個巨集:
void va_start ( va_list arg_ptr, prev_param ); /* ansi version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );
在這些巨集中,va就是variable argument(可變引數)的意思;arg_ptr是指向可變參數列的指標;prev_param則指可變參數列的前乙個固定引數;type為可變引數的型別。va_list也是乙個巨集,其定義為typedef char * va_list,實質上是一char型指標。char型指標的特點是++、--操作對其作用的結果是增1和減1(因為sizeof(char)為1),與之不同的是int等其它型別指標的++、--操作對其作用的結果是增sizeof(type)或減sizeof(type),而且sizeof(type)大於1。
通過va_start巨集我們可以取得可變參數列的首指標,這個巨集的定義為:
#define va_start ( ap, v ) ( ap = (va_list)&v + _intsizeof(v) )
#define _intsizeof(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) & ~( sizeof( int ) - 1 ) )
#define va_arg(list, mode) ((mode *)(list =/
(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &/
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]
對這個巨集的具體含義我們將在後面深入討論。
而va_end巨集被用來結束可變引數的獲取,其定義為:
#define va_end ( list )
可以看出,va_end ( list )實際上被定義為空,沒有任何真實對應的**,用於**對稱,與va_start對應;另外,它還可能發揮**的"自注釋"作用。所謂**的"自注釋",指的是**能自己注釋自己。
下面我們以具體的例子來說明以上三個巨集的使用方法。
2、乙個簡單的例子
#include
/* 函式名:max
* 功能:返回n個整數中的最大值
* 引數:num:整數的個數 ...:num個輸入的整數
* 返回值:求得的最大整數
int max ( int num, ... )
int m = -0x7fffffff; /* 32系統中最小的整數 */
va_list ap;
va_start ( ap, num );
for ( int i= 0; i< num; i++ )
int t = va_arg (ap, int);
if ( t > m )
m = t;
va_end (ap);
return m;
/* 主函式呼叫max */
int main ( int argc, char* ar** )
int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5個整數中的最大值 */
cout << n;
return 0;
函式max中首先定義了可變參數列指標ap,而後通過va_start ( ap, num )取得了參數列首位址(賦給了ap),其後的for迴圈則用來遍歷可變參數列。這種遍歷方式與我們在資料結構教材中經常看到的遍歷方式是類似的。
函式max看起來簡潔明瞭,但是實際上printf的實現卻遠比這複雜。max函式之所以看起來簡單,是因為:
(1) max函式可變參數列的長度是已知的,通過num引數傳入;
(2) max函式可變參數列中引數的型別是已知的,都為int型。
而printf函式則沒有這麼幸運。首先,printf函式可變引數的個數不能輕易的得到,而可變引數的型別也不是固定的,需由格式字串進行識別(由%f、%d、%s等確定),因此則涉及到可變參數列的更複雜應用。
下面我們以例項來分析可變參數列的高階應用。
c 語言可變引數
1 當無法列出傳遞函式的所有實參的型別和數目時,可用省略號指定參數列 void foo void foo parm list,2 函式引數的傳遞原理 函式引數是以資料結構 棧的形式訪問,從右至左入棧.eg include void fun int a,int main output 12 343 獲...
c語言可變引數
ifdef debug print info x printk x,else print info x endif 一 什麼是可變引數 我們在c語言程式設計中有時會遇到一些引數個數可變的函式,例如printf 函式,其函式原型為 int printf const char format,它除了有乙個...
C語言可變引數
在gnu c中,巨集可以接受可變數目的引數,就象函式一樣,例如 1 2 define pr debug fmt,arg.printk kern debug fmt,arg 用可變引數巨集 variadic macros 傳遞可變參數列 你可能很熟悉在函式中使用可變參數列,如 1 voidprintf...