? ? ? ?函數原型: int printf(const char *format[,argument]...)
?????? 返 回 值: 成功則返回實際輸出的字符數,失敗返回-1.
?函數說明:
???????在printf()函數中,format后面的參數個數不確定,且類型也不確定,這些參數都存放在棧內.調用printf()函數時,根據format里的格式("%d %f...")依次將棧里參數取出.而取出動作要用到va_arg、va_end、va_start這三個宏定義,再加上va_list.
???? (1)va_list事實上是一char *類型,即:
??????????? typedef char* va_list;
???? (2)三個宏定義:
??????????? #define _INTSIZEOF(n)??? ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )?
????????????#define va_start(ap,v)???? ( ap = (va_list)&v + _INTSIZEOF(v) )?
????????????#define va_arg(ap,type)? ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )?
????????????#define va_end(ap)????????? ( ap = (va_list)0 )?
?? 【attention】C語言中可變參數的原理---printf()函數?
??????????? int printf(const char* format,...);???
????? 使用過C語言的人所再熟悉不過的printf函數原型,它的參數中就有固定參數format和可變參數(用”…”表示).而程序員又可以用各種方式來調用printf,如:?
??????????? printf("%d ",value);???
??????????? printf("%s ",str); ??
??????????? printf("the number is %d,string is:%s ",value,str);?
?????? 可以看出,該函數的參數格式不固定,參數類型不固定.在C語言中使用宏來處理這些可變參數.這些宏看起來很復雜,其實原理挺簡單,即根據參數入棧的特點從最靠近第一個可變參數的固定參數開始,依次獲取每個可變參數的地址.
?(1)宏va_start
????? 通過該宏定義可以獲取到可變參數表的首地址,并將該地址賦給指針ap.
?(2)宏va_arg
????? 通過該宏定義可以獲取當前ap所指向的可變參數,并將指針ap指向下一個可變參數.注意,該宏的第二個參數為類型.
?(3)宏va_end
??????通過該宏定義可以結束可變參數的獲取.
????? 程序員通過這三個宏定義就可以實現對可變參數的處理.例如:
? ?#include <stdio.h> ?
??
typedef char* va_list; ??
? ?#define _INTSIZEOF(n) ? ?((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) ??
? ?#define va_start(ap,v) ? ( ap = (va_list)&v + _INTSIZEOF(v) ) ??
? ?#define va_arg(ap,type) ?( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) ??
? ?#define va_end(ap) ? ? ? ( ap = (va_list)0 ) ??
??
int cal_val(int c, ...) ??
{ ??
? ? int sum = c; ??
? ? va_list ap; ? ? ? ? ? ? ?//聲明指向char型的指針 ?
? ? va_start(ap,c); ? ? ? ? ?//獲取可變參數列表的首地址,并賦給指針ap ?
??
? ? c = va_arg(ap,int); ? ? ?//從可變參數列表中獲取到第一個參數(返回值即為參數) ?
? ? while(0 != c) ??
? ? { ??
? ? ? ? sum += c; ??
? ? ? ? c = va_arg(ap,int); ?//循環的從可變參數列表中獲取到參數(返回值即為參數) ?
? ? } ?
? ? va_end(ap); ? ? ? ? ? ? ?//結束從可變參數列表中獲取參數 ?
? ? return sum; ??
} ? ?
? ?
int main(int argc, char* argv[]) ??
{ ??
? ? int value1; ?
? ? ??
? ? value1 = cal_val(1,2,3,4,5,6,7,8,9,0); ??
? ? printf("value1=%d/n",value1); ?
? ? value2 = cal_val(6,7,8,9,0); ??
? ? printf("value2=%d/n",value2); ?
? ? ??
? ? return 0; ??
} ??