1. 程式人生 > >實現自己的printf列印 -- 可變引數的函式

實現自己的printf列印 -- 可變引數的函式

/*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 ))))