您的位置:首页 > 编程语言 > C语言/C++

C语言可变长参数实现原理

2014-05-14 20:30 232 查看


(1) C语言可变参数

我们可以从C语言的printf得出可变参数的作用,printf函数的原型如下:
int printf ( const char * format, ... );

通过使用可变个数参数,就是传入的参数个数是可变的,如printf需要根据format实参传入多个实参。


(2) C语言可变参数的使用

下面一个函数myprintf是自己实现的比较简单的printf函数,不完整但是可以说明可变参数的用法。

/*

* Author: enough

*/

#include <stdio.h>

#include <stdarg.h>

#include <unistd.h>

#include <string.h>

void myprintf(char *format, ...) {

va_list ap;

int pos = 0;

int int_val = 0;

float f_val;

char buf[64];

memset(buf, 0, 64);

// 得到所有的参数放到下一个list中ap中

va_start(ap, format);

while (format[pos] != '\0') {

// 判断'%',表示要得到下一个参数

if (format[pos] == '%') {

pos ++;

switch(format[pos]) {

case 'd':

case 'u':

// 得到ap中的下一个参数

int_val = va_arg(ap, int);

sprintf(buf, "%d", int_val);

// 将数据写到标准输出

write(STDOUT_FILENO, buf, strlen(buf));

memset(buf, 0, 64);

pos ++;

break;

case 'f':

// 得到ap中的下一个参数

f_val = (float)va_arg(ap, double);

sprintf(buf, "%f", f_val);

// 将数据写到标准输出

write(STDOUT_FILENO, buf, strlen(buf));

memset(buf, 0, 64);

pos ++;

break;

default:

break;

}

} else {

write(STDOUT_FILENO, &(format[pos]), 1);

pos ++;

}

}

}

int main(void){

myprintf("this is a testing, i = %d, u = %u, f = %f\n", -1, 5, 0.2);

return 0;

}


程序的数据结果如下:

enough@enough-desktop:~/test/valist$ ./main
this is a testing, i = -1, u = 5, f = 0.200000





(3) 实现

下面介绍C语言可变长度参数的实现,其实现与一个数据结构(va_list)和三个宏(va_start, va_end, va_arg)相关,从源码中可以看到这些实现下面的来自linux内核源码中的文件(include/acpi/platform/acenv.h)

#ifndef _VALIST

#define _VALIST

typedef char *va_list;

#endif /* _VALIST */

/*

* Storage alignment properties

*/

#define _AUPBND (sizeof (acpi_native_int) - 1)

#define _ADNBND (sizeof (acpi_native_int) - 1)

/*

* Variable argument list macro definitions

*/

#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))

#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))

#define va_end(ap) (void) 0

#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

a) va_list

从实现中可以看出va_list类型实际上就是一个指针;

b) va_start

这个宏的作用是将T所指向的参数后面的内容放到ap中,其中_bnd (A,_AUPBND)是返回A的size并与系统的机器位数对齐,因为参数在栈中的地址一定是与系统的字长对齐的,其中acpi_native_int就表示机器字长;

c) va_end

这个宏的作用就是返回0;

d) va_arg

这个宏的作用是取得ap指向的当前的参数,并将ap指向参数列表中的下一个参数。(转载自:http://blog.chinaunix.net/uid-13991680-id-4234493.html)



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: