我们先看看可变参数函数是怎样用的?
printf("%d",value);
printf("%s",str);
printf("%d %s",value,str);
printf函数的声明为:
int printf(char const* const _Format,...);
//其中三个点表示变参宏
可变参数函数的原理:
可变参数列表的实现是由stdarg.h中几个宏组成的:va_list,va_start(),va_arg(),va_end()
va_list:
typedef char* va_list; //其实就是字符指针类型
va_start,va_arg,va_end
#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))
#define __crt_va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
#define __crt_va_end(ap) ((void)(ap = (va_list)0))
其中_INTSIZEOF()定义为:
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
//以int所占字节数操作
//如果int占4字节,则以4字节对齐读取数据
_ADDRESSOF()定义为:
#define _ADDRESSOF(v) (&const_cast<char&>(reinterpret_cast<const volatile char&>(v)))
//目的是首先将传入的引用转化为char类型的引用,然后使用&取址
_ADDRESSOF()详见 STL实现细节之addressof()
我们先不考虑&操作符重载的情况,那么
va_start的宏定义为:
#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)&v + ((sizeof(v) + sizeof(int) - 1) & ~(sizeof(int) - 1))))
//ap指向可变参数的第一个参数位置处
va_arg宏定义中,(ap += _INTSIZEOF(t))使ap指向下一个参数的位置,(ap += _INTSIZEOF(t)) - _INTSIZEOF(t))则返回当前参数的位置。
va_end将ap指针设为空。
实现printf函数
#include<stdio.h>
#include<stdarg.h>
#include<stdlib.h>
void Myprint(const char* str, ...)
{
double varglt = 0;
int vargint = 0;
char* vargpch = NULL;
char vargch = 0;
//char* pfmt = NULL;
va_list vp=NULL;
va_start(vp, str);
while (*str) {
if (*str == '%') {
switch (*(++str))
{
case 'c':
vargch = va_arg(vp,char);
putchar(vargch);
break;
case 'd':
case 'i': {
vargint = va_arg(vp, int);
char strint[12] = { 0 };
int i = 0;
while (vargint != 0) {
strint[i] = vargint % 10;
vargint /= 10;
i++;
}
strint[i] = '\0';
for (int j = i - 1; j >= 0; j--) {
putchar(strint[j] + '0');
}
break;
}
case 'f': {
varglt = va_arg(vp, double);
char strdou[320] = { 0 };
int i = 0;
sprintf_s(strdou, "%f", varglt);
while (strdou[i]) {
putchar(strdou[i]);
i++;
}
break;
}
case 's':
vargpch = va_arg(vp, char*);
while (*vargpch)
{
putchar(*vargpch);
vargpch++;
}
break;
default:
putchar(*(str - 1));
putchar(*str);
break;
}
str++;
}
else {
putchar(*str);
str++;
}
}
va_end(vp);
}
int main() {
float f = 1.001f;
Myprint("%c %d %f\n", 'c','a',f);
system("pause");
}