配色: 字号:
MTK优美代码赏析8可变参数的C函数
2012-08-06 | 阅:  转:  |  分享 
  
MTK优美代码赏析8:可变参数的C函数

对于可变参数函数,自己一直以来都很关注,尤其当自己刚才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(charfmt,…)函数实现,部分内容摘自:《用库函数stdarg.h实现函数参数的可变》http://blog.sina.com.cn/s/blog_4ce3d23e0100efm3.html

dbg_print代码

#define?MAXCHARS?512#define?MAXFRACT?????10000#define?NumFract????????4static?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?(p?!=?‘%’)?{//当前字符不是%号时,直接赋值,是%表示需要对输入进行转化?bp++=?p;?continue;?}?switch?(++p)?{?case?‘d’://十进制数?ival=?va_arg(ap,?int);//返回参数列表中指针ap所指的参数,返回类型为int,并使指针ap指向参数列表中下一个参数。?if?(ival?=?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?
?

?

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



代码

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



?



献花(0)
+1
(本文系小云蔡首藏)