實現自己的printf列印 -- 可變引數的函式
阿新 • • 發佈:2019-02-19
/*X86平臺,引數傳遞是基於堆疊來完成的,對記憶體使用時連續的*/
void printf_myself(const char *format, ...)
{
//char *ptr_s = &format;
int num; char ch; double d;
struct _student stu;
//const char *name_str;
/*指標操作,1取值,2指標自增(移動指標)*/
//char *s = format; // char *s = **ptr_s;
va_list p;
printf("str = %s \n", format);
va_start(p,format);
num = va_arg(p,int);
printf("num = %d\n", num);
stu = va_arg(p,struct _student);
printf("stu.num = %d\n", stu.num);
printf("stu.name = %s\n", stu.name);
printf("stu.age = %d\n", stu.age);
num = va_arg(p,int);
printf("num = %d \n", num);
ch = va_arg(p,int);
printf("ch = %c\n", ch);
d = va_arg(p,double);
printf("num = %f\n", d);
va_end(p);
}
其實實現可變引數列表是如此的簡單,哈哈,
一句話來概括就是:
/X86平臺,引數傳遞是基於堆疊來完成的,對記憶體使用時連續的/
三步走!!!
1,取指標變數的值(不是所指向的值)
va_list p; //va_list 是一個字元指標變數的巨集 typedef char * va_list;
va_start(p,format );
這個操作將會使得指標format自增
2,取值 並 移動指標
num = va_arg(p,int);
va_arg()這個函式用來取出指標移動後所指向的地址的值,並移動p指標並以int型別移動指向,所以這裡是移動4個位元組。
va_end(p);
最後這句是把p指向了一個空指標,防止野指標。
參考:
INTSIZEOF 巨集,獲取型別佔用的空間長度,最小佔用長度為int的整數倍:
define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
VA_START巨集,獲取可變引數列表的第一個引數的地址(ap是型別為va_list的指標,v是可變引數最左邊的引數):
define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
VA_ARG巨集,獲取可變引數的當前引數,返回指定型別並將指標指向下一引數(t引數描述了當前引數的型別):
define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
VA_END巨集,清空va_list可變引數列表:
define va_end(ap) ( ap = (va_list)0 )ist)0 )))
)