C语言通用可变参数,C语言可变参数的另一种实现

大家熟知的C库函数printf函数就是一个可变参数函数,它是怎么实现的呢?不过他实现是有条件的,必须函数参数的入栈顺序为从右向左的顺序,也即函数的形参,在函数调用之前,必须是最右边的参数先入栈,并且参数都必须通过栈传递,以1个例子说明,如函数func(arg1, arg2,arg3),那么函数的堆栈应是:

38287304_1.jpg

ebp是帧指针寄存器,一般用来存取堆栈,有了堆栈结构,下面我们看看C可变参数的具体实现原理:

#include

enum {

ptChar,

ptInt,

ptFloat,

ptDouble,

};

void printSum(unsigned long paramFormat, ...)

{

/*高16位为可变参数类型,低16位为可变参数个数*/

int paramType = (paramFormat >> 16);

int paramNum = paramFormat & 0xffff;

/*?mFormat = ebp 8,第一个参数的地址*/

unsigned long *pArg = ?mFormat;

/*ebp 0x0c, 第二个参数地址*/

pArg ;

switch(paramType)

{

case ptChar:

{

int sum = 0;

for (int i = 0; i < paramNum; i )

{

char *pValue = (char *)pArg;

sum = *pValue;

pArg ;

}

printf("%d\n", sum);

}

break;

case ptInt:

{

int sum = 0;

for (int i = 0; i < paramNum; i )

{

int *pValue = (int *)pArg;

sum = *pValue;

pArg ;

}

printf("%d\n", sum);

}

break;

case ptFloat:

{

float sum = 0;

/**/

pArg ;

/*浮点参数,堆栈占8个字节,所以指针偏移为8*/

for (int i = 0; i < paramNum; i )

{

float *pValue = (float *)pArg;

sum = *pValue;

pArg ;

pArg ;

}

printf("%f\n", sum);

}

break;

case ptDouble:

{

double sum = 0;

/*双精度浮点参数,堆栈占8个字节,所以指针偏移为8*/

for (int i = 0; i < paramNum; i )

{

double *pValue = (double *)pArg;

sum = *pValue;

pArg ;

pArg ;

}

printf("%f\n", sum);

}

break;

default:

printf("unknowned type!\n");

break;

}

}

void main()

{

unsigned long paramFormat = 3;

char a = 1, b = 2, c = 3;

printSum(paramFormat, a, b, c);

paramFormat = ptInt << 16;

paramFormat = 3;

int ia = 1, ib = 2, ic = 3;

printSum(paramFormat, ia, ib, ic);

paramFormat = ptFloat << 16;

paramFormat = 3;

float fa = 1, fb = 2, fc = 3;

printSum(paramFormat, fa, fb, fc);

paramFormat = ptDouble << 16;

paramFormat = 3;

double da = 1, db = 2, dc = 3;

printSum(paramFormat, da, db, dc);

}

上面这种方法对函数参数的入栈顺序有限制,必须从右向左入栈,这就是为什么pascal调用方式不能实现printf的原因,并且函数形参都要通过栈来传递,这对有些编译器为了优化处理,函数参数通过寄存器来传递,从而不满足要求。鉴于次,本文采用C 的默认形参实现可变参数的方法,没有上面的这些限制,下面是实现代码:

#include

enum {

ptChar,

ptInt,

ptFloat,

ptDouble,

};

void printSum(unsigned long paramType,

void *arg1 = NULL,

void *arg2 = NULL,

void *arg3 = NULL,

void *arg4 = NULL,

void *arg5 = NULL,

void *arg6 = NULL,

void *arg7 = NULL,

void *arg8 = NULL,

void *arg9 = NULL,

void *arg10 = NULL)

{

void *arg[10] = {

arg1,

arg2,

arg3,

arg4,

arg5,

arg6,

arg7,

arg8,

arg9,

arg10,

};

switch(paramType)

{

case ptChar:

{

int sum = 0;

for (int i = 0; i < 10; i )

{

if (arg[i] != NULL)

{

char *pValue = (char *)arg[i];

sum = *pValue;

}

else

break;

}

printf("%d\n", sum);

}

break;

case ptInt:

{

int sum = 0;

for (int i = 0; i < 10; i )

{

if (arg[i] != NULL)

{

int *pValue = (int *)arg[i];

sum = *pValue;

}

else

break;

}

printf("%d\n", sum);

}

break;

case ptFloat:

{

float sum = 0;

for (int i = 0; i < 10; i )

{

if (arg[i] != NULL)

{

float *pValue = (float *)arg[i];

sum = *pValue;

}

else

break;

}

printf("%f\n", sum);

}

break;

case ptDouble:

{

double sum = 0;

for (int i = 0; i < 10; i )

{

if (arg[i] != NULL)

{

double *pValue = (double *)arg[i];

sum = *pValue;

}

else

break;

}

printf("%f\n", sum);

}

break;

default:

printf("unknowned type!\n");

break;

}

}

void main()

{

unsigned long paramType = ptChar;

char a = 1, b = 2, c = 3;

printSum(paramType, &a, &b, &c);

paramType = ptInt;

int ia = 1, ib = 2, ic = 3;

printSum(paramType, &ia, &ib, &ic);

paramType = ptFloat;

float fa = 1, fb = 2, fc = 3;

printSum(paramType, &fa, &fb, &fc);

paramType = ptDouble;

double da = 1, db = 2, dc = 3;

printSum(paramType, &da, &db, &dc);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值