一、是否可以只使用一組整數參數來複制任意類型的數值?(理論上,只要函數參數個數支持,這僅是對內存解釋的不同)
關於Printf的實現 第一個參數必須是一個字符串。//??
1.在知道第一個參數類型的情況下,就可以對其進行存取。
2.一旦第n個參數被存取,第n+1個參數就可以在僅知道類型的情況下進行存取。
3.按這種方式存取一個參數所需的時間不應太多。
大多數c語言都是通過一組VARARGS來實現上述目的。
帶有可變參數列表的函數,必須在函數定義的首部使用va_alist和va_dcl 宏。
#include<vararg.h>
void error (va_alist) va_dcl
varargs.h的一個典型實現
typedef char *va_list;
#define va_dcl int va_alist;
#define va_start(list) l list=(char *)&va_alist
#define va_end(list)
#define va_arg(list,mode) ((mode*)(list+=sizeof(mode)))[-1] //可以看到這裏限制後面的參數是順序存取。
所以上面error被擴展爲
typedef char* va_list
void error(va_alist) int va_alist /*表面看來,僅僅是一個整型參數*/
這個例子的假定:底層的c語言實現要求函數參數在內存中連續存儲,這樣我們只需知道當前參數的地址,就能依次訪問參數列表中的其他參數。
因此,vararg.h的這個實現中,va_list就只是一個簡單的字符指針。宏va_start把它的參數設置爲va_alist的地址,並進行了類型轉換,而宏
va_end 則什麼也不做。
回到??的地方,我們看到這組宏定義,並沒有標識給定的參數數目,所以使用varargs系列宏的每個程序,都有責任通過確立某種約定或慣例來標誌參數列表的結束。而printf函數使用格式字符串作爲第一個參數,通過它來識別參數數目與類型。
例子:使用vprintf函數來實現printf,前者直接使用va_list類型參數。
#include<varargs.h>
int printf(va_alist) va_dcl
{
va_list ap;
char* format;
int n;
va_start(ap);//ap指向va_alist參數列表
format=va_arg(ap,char*);//獲取char* 類型參數,同時更新ap指向下一個參數起始位置。
n=vprintf(format,ap);
va_end(ap); //不同實現,可能要求釋放內存。
return n;
}
二、ANSI的varargs.h
ANSI提供了一組新的標準來實現可變參數功能。
具有可變參數列表的函數,他們的第一個參數的類型在每次調用時實際上都是不變的。類似printf這樣的函數,可以通過檢查它的第一個參數,來確定它的第2個參數的類型。但是,從參數列表中我們不能確定第一個參數的類型。
使用stdarg.h的函數至少有一個固定類型的參數,後面可以跟一組未知數目,位置類型的參數。
stdarg.h文件中沒有va_arg和va_dcl宏,使用stdarg.h的函數直接聲明其固定參數,把最後一個固定定參數作爲va_sart宏的參數,來訪問可變參數。
列子:
#include <stdarg,h.
int printf ( char * format,..)
{
va_list ap;
int n;
va_start(ap,format);//多了一個format,ap 指向後續可變參數
n=vprintf(format,ap);
va_end(ap);
return n;
}