例如:
其實這就是可變參數,我們看看printf函數的原型,是這樣的
我們可以看到printf函數除了有一個固定的format參數以外,其他都是可變的,因此纔有了不同的調用方法
既然這個函數這麼神奇,那麼在私底下他到底是怎麼實現的呢?接下來就這個問題,我們來一探究竟,同時希望可以幫助其他和我一樣對此不瞭解的人,也讓我加深對可變參數的理解,這裏我們就模擬實現一下printf函數。
在可變參數的模擬實現中,我們會用到以下這幾個宏,這裏我在msdn中搜到他們
va在這裏是variable-argument(可變參數)的意思.這些宏定義在stdarg.h中,所以用到可變參數的程序應該包含這個頭文件,接下來我們就來寫一個簡單函數模擬實現一下printf函數
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void display(int ret) //打印整數
{
if(ret>9)
{
display(ret/10);
}
putchar(ret%10+'0');
}
void print(char *format, ...) //模擬實現printf函數
{
va_list arg; //char *
va_start(arg, format);
while(*format != '\0')
{
int i = 0;
if(*format == 's') //出現s,就打印一個字符串
{
char* ret = NULL;
ret = va_arg(arg, char*);
while(*ret != '\0')
{
putchar(*ret);
ret++;
}
}
else if(*format == 'c') //出現c,就打印一個字符
putchar(va_arg(arg, char));
else if(*format == 'd') //出現d,就打印整型,這裏沒有打印負數
{
int ret = 0;
ret = va_arg(arg, int);
display(ret);
}
else //其他照常打印
putchar(*format);
format++;
}
va_end(arg);
}
int main()
{
print("s ccc d%.\n","hello",'b','i','t',100);
return 0;
}
首先爲MAIN函數開闢一塊空間
然後在MAIN函數中調用printf函數,調用的時候有會進行傳參
然後通過內存進行訪問,模擬實現了printf函數
從這個函數的實現可以看到,我們使用可變參數應該有以下步驟:
1)首先在函數裏定義一個va_list型的變量(依照個人情況),這裏是arg,這個變量是指向參數的指針.
2)然後用va_start宏初始化變量arg。
3)然後用va_arg返回可變的參數,並賦值,va_arg的第二個參數是你要返回的參數的類型,這裏是char型(返回字符串“hello”,字符‘b’,‘i’,‘t’),int型(返回100). 對應的返回值可以在程序中找到。
4)最後用va_end宏結束可變參數的獲取。
接下我們看看可變參數在編譯器中的處理情況
typedef System::ArgIterator va_list;
#else
typedef char * va_list;
#endif /* _M_CEE_PURE */
#define _VA_LIST_DEFINED
#endif
#ifdef __cplusplus
#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v) ( &(v) )
#endif
#if defined(_M_IA64) && !defined(_M_CEE_PURE)
#define _VA_ALIGN 8
#define _SLOTSIZEOF(t) ( (sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1) )
#define _VA_STRUCT_ALIGN 16
#define _ALIGNOF(ap) ((((ap)+_VA_STRUCT_ALIGN - 1) & ~(_VA_STRUCT_ALIGN -1)) \
- (ap))
#define _APALIGN(t,ap) (__alignof(t) > 8 ? _ALIGNOF((uintptr_t) ap) : 0)
#else
#define _SLOTSIZEOF(t) (sizeof(t))
#define _APALIGN(t,ap) (__alignof(t))
#endif
#if defined(_M_CEE)
extern void __cdecl __va_start(va_list*, ...);
extern void * __cdecl __va_arg(va_list*, ...);
extern void __cdecl __va_end(va_list*);
#define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \
__alignof(v), _ADDRESSOF(v)) )
#define _crt_va_arg(ap,t) ( *(t *)__va_arg(&ap, _SLOTSIZEOF(t), \
_APALIGN(t,ap), (t *)0) )
#define _crt_va_end(ap) ( __va_end(&ap) )
#elif defined(_M_IX86)
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_IA64)
va_arg()取得類型的可變參數值
#define va_arg _crt_va_arg
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )