德馨轩

斯是陋室,惟吾德馨。QQ:275000205

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

对于可变参数函数,自己一直以来都很关注,尤其当自己刚才C#上转到C时,一度曾研究C上的面向对象,将类似printf的函数归类为面向对象里的函数多态,当时只是一个主观感受。今日仔细看了下代码的实现,发现使用C提供的公共接口是可以实现的,但这些接口是如何实现的就不知了。。。

文件:stdarg.h

gcc中的定义为:

/* Define the standard macros for the user,
if this invocation was from the user program.  
*/
/* Define the standard macros for the user,   if this invocation was from the user program.  */

#define va_start(v,l) __builtin_va_start(v,l)

#define va_end(v) __builtin_va_end(v)

#define va_arg(v,l) __builtin_va_arg(v,l)

#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L

#define va_copy(d,s) __builtin_va_copy(d,s)

#endif

 

 

 下面看dbg_print(char *fmt,…)函数实现,部分内容摘自:《用库函数stdarg.h实现函数参数的可变》http://blog.sina.com.cn/s/blog_4ce3d23e0100efm3.html

dbg_print代码
#define MAXCHARS 512

#define MAXFRACT     10000

#define NumFract        4

static void itoa(char **buf, int i, int base);

void itof(char **buf, int i);

char print_buf[MAXCHARS];
void dbg_print(char *fmt,…)

{

#if (!defined(IC_MODULE_TEST))

va_list ap;
//定义一个指向个数可变的参数列表指针;

double dval;

int ival;

char *p, *sval;

char *bp, cval;

int fract;

unsigned 
short len;

 bp
= print_buf;

 
*bp= 0;

 

 va_start (ap, fmt);
//使参数列表指针ap指向函数参数列表中的第一个可选参数,

/*

说明:fmt是位于第一个可选参数之前的固定参数,(或者说,最后一个固定参数;…之前的一个参数),函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是void va_test(char a, char b, char c, …),则它的固定参数依次是a,b,c,最后一个固定参数fmt为c,因此就是va_start(ap, c)。

*/

 
for (p= fmt; *p; p++)//逐个字符处理输入的fmt字符串参数

 {

 
if (*!= ‘%’)

 {
//当前字符不是%号时,直接赋值,是%表示需要对输入进行转化

 
*bp++= *p;

 
continue;

 }

 
switch (*++p) {

 
case ‘d’://十进制数

 ival
= va_arg(ap, int);//返回参数列表中指针ap所指的参数,返回类型为int,并使指针ap指向参数列表中下一个参数。

 
if (ival < 0){

 
*bp++= ‘-’;

  ival
= -ival;

 }

 itoa (
&bp, ival, 10);

 
break;

 

 
case ‘o’://八进制

 ival
= va_arg(ap, int);

 
if (ival < 0){

 
*bp++= ‘-’;

  ival
= -ival;

 }

 
*bp++= ’0′;

 itoa (
&bp, ival, 8);

 
break;

 

 
case ‘x’://16进制

 ival
= va_arg(ap, int);

 
if (ival < 0){

  
*bp++= ‘-’;

  ival
= -ival;

 }

 
*bp++= ’0′;

 
*bp++= ‘x’;

 itoa (
&bp, ival, 16);

 
break;

 

 
case ‘c’://字符

 cval
= va_arg(ap, int);

 
*bp++= cval;

 
break;

 

 
case ‘f’://浮点数,这个处理比较特殊

 dval
= va_arg(ap, double);

 
if (dval < 0){

 
*bp++= ‘-’;

 dval
= -dval;

 }

 
if (dval >= 1.0)//大于1.0时

 itoa (
&bp, (int)dval, 10);//强制转化为整数后按十进制取小数点前的值

   
else//否则直接输出0

 
*bp++= ’0′;

 
*bp++= ‘.’;//设置小数点字符

 fract
= (int)((dval- (double)(int)dval)*(double)(MAXFRACT));//将.后的值转化为整数

 itof(
&bp, fract);//将这个整数转化为字符

 
break;

 

 
case ‘s’://string

 
for (sval = va_arg(ap, char *) ; *sval ; sval++ )

  
*bp++= *sval;

 
break;

 }

 }

//补充一个: va_copy(dest, src):dest,src的类型都是va_list,va_copy()用于复制参数列表指针,将dest初始化为src。

 
*bp= 0;

 len 
= (unsigned short)(bp – print_buf);

 
//#if 1  将数据写入串口

 #ifdef __DMA_UART_VIRTUAL_FIFO__

 
for (bp= print_buf; *bp; bp++)

 {

 PutUARTByte(DBG_PRINT_PORT,
*bp);

 }

 
#else

 BMT_PutBytes(DBG_PRINT_PORT,(kal_uint8 
*)print_buf,len);

 
#endif

 va_end (ap);
//清空参数列表,并置参数指针arg_ptr无效。说明:指针arg_ptr被置无效后,可以通过调用 va_start()、va_copy()恢复ap。每次调用va_start() / va_copy()后,必须得有相应的va_end()与之匹配。参数指针可以在参数列表中随意地来回移动,但必须在va_start() … va_end()之内。

#endif

}

//功能:把10进制数字转换为数字字符串。

void itof(char **buf, int i)

{

 
char *s;

#define LEN 20

 
int rem, j;

 
static char rev[LEN+1];

 rev[LEN] 
= 0;

 s 
= &rev[LEN];//s指向rev末尾

 
for (j= 0 ; j < NumFract ; j++)

 {

 rem 
= i % 10;//和下面i/=10配合,依次取个位,十位,百位,千位

 
*–s = rem + ’0′;//加上字符0,将数字变为数字字符

 i 
/= 10;

 }

 
while (*s)

 {

 (
*buf)[0= *s++;//unicode 转 assic

 
++(*buf);

 }

}

//功能:把一数字转换为数字字符串,base表示type, 8 10 16 32等

static void itoa(char **buf, int i, int base)

{

 
char *s;

#define LEN 20

 
int rem;

 
static char rev[LEN+1];

 rev[LEN] 
= 0;

 
if (i == 0)

 {

 (
*buf)[0= ’0′;

 
++(*buf);

 
return;

 }

 s 
= &rev[LEN];

 
while (i)

 {

 rem 
= i % base;

 
if (rem < 10)

 
*–s = rem + ’0′;

 
else if (base == 16)

 
*–s = “abcdef”[rem - 10];

 i 
/= base;

 }

 
while (*s)

 {

 (
*buf)[0= *s++;

 
++(*buf);

 }

}

 

 

 其他地方有对这个宏的定义为:

代码
typedef int *va_list[1];

#define va_start(ap, parmN) (void)(*(ap) = __va_start(parmN))

#define va_arg(ap, type) __va_arg(*(ap), type)

#define va_copy(dest, src) ((void)(*(dest) = *(src)))

#define va_end(ap) ((void)(*(ap) = 0))

#undef tolower

#undef isdigit

#define isdigit(c) (((c) >= ’0′) && ((c) <= ’9′))

#define tolower(c) (((c)>=’A’ && (c)<=’Z')?((c)+0×20):(c))

 

 

 

posted on 2010-10-27 22:22  Anpher Zhang  阅读(860)  评论(0编辑  收藏  举报