函式原型: 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
通過該巨集定義可以結束可變引數的獲取.
程式設計師通過這三個巨集定義就可以實現對可變引數的處理.例如:
C語言中可變引數函式實現原理
c函式呼叫的棧結構 可變引數函式的實現與函式呼叫的棧結構密切相關,正常情況下c的函式引數入棧規則為 stdcall,它是從右到左的,即函式中的最右邊的引數最先入棧。例如,對於函式 void fun int a,int b,int c 其棧結構為 0x1ffc d 0x2000 a 0x2004 b ...
C語言中可變引數函式實現原理
說的非常詳細,但是有部分口誤,希望只吸取精華 c函式呼叫的棧結構 可變引數函式的實現與函式呼叫的棧結構密切相關,正常情況下c的函式引數入棧規則為 stdcall,它是從右到左的,即函式中的最右邊的引數最先入棧。例如,對於函式 void fun int a,int b,int c 其棧結構為 0x1f...
C語言中的可變引數
1 需要標頭檔案 include 2 函式定義 void logcmd int arg0,void logcmd char arg0,3 解析 i 數字型別 void logcmd int n,其中n表示引數的個數,n之後才是真正的引數。呼叫如 logcmd 0 logcmd 1,9 logcmd ...