C语言——可变参数
C語言——可變參數
宗旨:技術的學習是有限的,分享的精神是無限的。
1、目前為止,見過比較熟悉的可變參數的函數就是printf()函數
int printf(const char *format, …);<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">?</span>2、可變參數宏
void va_start(va_list arg_ptr, prev_param); type va_arg(va_list arg_ptr, type); void va_end(va_list arg_ptr);va_list:用來保存宏va_start、va_arg和va_end所需信息的一種類型。為了訪問變長參數列表中的參數,必須聲明va_list類型的一個對象??????定義:?typedef char *? va_list;
va_start:訪問變長參數列表中的參數之前使用的宏,它初始化用va_list聲明的對象,初始化結果供宏va_arg和va_end使用;
va_arg:?展開成一個表達式的宏,該表達式具有變長參數列表中下一個參數的值和類型。每次調用va_arg都會修改用va_list聲明的對象,從而使該對象指向參數列表中的下一個參數;
va_end:該宏使程序能夠從變長參數列表用宏va_start引用的函數中正常返回。
C語言內存管理中,我們提到函數的參數存放在棧中。通過反匯編可知,可變參數是從右向左依次壓棧的,所以第一個參數靠近棧頂,最后一個參數靠近棧底。這些參數在內存中是連續存放的,每個參數都4字節對齊。
?
3、stdarg.h的一種實現
/* stdarg.h standard header */ #ifndef _STDARG #define _STDARG /* type definitions */ typedef char *va_list; /* macros */ #define va_arg(ap, T) \(* (T *)(((ap) += _Bnd(T, 3U)) - _Bnd(T, 3U))) #define va_end(ap) (void)0 #define va_start(ap, A) \(void)((ap) = (char *)&(A) + _Bnd(A, 3U)) #define _Bnd(X, bnd) (sizeof (X) + (bnd) & ~(bnd)) #endif /*<span style="font-family: Arial, Helvetica, sans-serif;">_STDARG</span> */這個頭文件中的內部宏定義將類型或變量的長度對齊到字節的整數倍,例如_Bnd(char, 3U)的值是4,_Bnd(int, 3U)也是4
?
4、可變參數函數實現思路
(1)首先在函數里定義一個va_list型的變量,這里是arg_ptr,這個變?量是指向參數的指針。
(2)然后用va_start宏初始化變量arg_ptr,這個宏的第二個參數是第?一個可變參數的前一個參數,是一個固定的參數。
(3)然后用va_arg返回可變的參數,并賦值給整數j.?va_arg的第二個參數是你要返回的參數的類型,這里是int型。
(4)最后用va_end宏結束可變參數的獲取.然后你就可以在函數里使?用第二個參數了.如果函數有多個可變參數的,依次調用va_arg獲?取各個參數。
?
5、myprintf函數實現
#include <stdio.h> #include <stdarg.h>void myprintf(const char *format, ...) {va_list ap;char c;va_start(ap, format);while(c = *format++){switch(c){case 'c':{char ch = va_arg(ap, int);putchar(ch);break;}case 's':{char *p = va_arg(ap, char *);fputs(p, stdout);break;}default:putchar(c);}}va_end(ap); }int main(void) {myprintf("c\ts\n", '1', "hello");return 0; }總結
- 上一篇: linux之svn回滚/回退到某个版本
- 下一篇: 孙鑫6菜单