打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C语言可变参数的另一种实现

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

2013年08月16日 | 作者:佚名 | 来源:比特网


摘要:  大家熟知的C库函数printf函数就是一个可变参数函数,它是怎么实现的呢?不过他实现是有条件的,必须函数参数的入栈顺序为从右向左的顺序,也即函数的形参,在函数调用之前,必须是最右边的参数先入栈,并且参数都必须通过栈...

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

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);

}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
va_start va_end函数应用
很好的c 和Python混合编程文章
C可变参数实现原理
va_list、va_start、va_arg、va_end的原理与使用 - 浪迹天涯 -...
C调用Python函数相关代码示例剖析
学生成绩管理系统(C语言)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服