linux下可变参数及宏定义封装函数

以下函数包含内容:使用宏封装可变参函数 可变参数。比较简单,无注释。

 

两个函数均可以打印出调用者的文件、函数、行号信息。需要参考该代码的,拿走不谢!

 

#include 

#include 

#include 


#define BUF_LEN 500

 

/* 封装调试函数 */

#define macroFunc(info)  (transparentMacroFunc(__FILE__, __func__, __LINE__, (info)))

 

/* 封装带可变参数的调试函数 */

#define macroFuncVargs(fmt, ...)  (transparentMacroFuncVargs(__FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__))

 

/* file, func, line为宏封装好的入参,info为调用者传入参数 */

int transparentMacroFunc(const char *file, const char *func, int line, const char *info)

{

   printf("File:%s, Func:%s, Line:%d, info:%s\n", file, func, line, info);

   return 0;

}

 

/* 同上,只不过改为可变参数 */

int transparentMacroFuncVargs(const char *file, const char *func, int line, const char *fmt, ...)

{

char buf[BUF_LEN];

va_list args;

 

memset(buf, 0, BUF_LEN);

 

snprintf(buf, BUF_LEN, "File: %s, Func: %s, Line: %d info: ", file, func, line);

/* 可变参的相关函数稍后会有解释 */

va_start(args, fmt);

vsnprintf(buf + strlen(buf), BUF_LEN - strlen(buf), fmt, args);

va_end(args);

 

printf("%s\n", buf);

 

return 0;

}

 

 

/* 测试主函数 */

int main()

{

macroFunc("info");

int a = 2;

macroFuncVargs("%d", a);

return 0;

}

 

-------------------------- -------------------   我是代码分隔线 ----------------------- ------------------ ---

 

一、关于宏封装函数

宏只是一个简单的替换,所以调试代码如果遇到编译错误,就在调用出扩展开,这样能更快的定位问题。

 

二、关于可变参数

Linux的可变参函数在头文件stdarg.h中定义

 

 #include 

 

 void va_start(va_list ap, last);

 type va_arg(va_list ap, type);

 void va_end(va_list ap);

 void va_copy(va_list dest, va_list src);

 

Man手册中说明它们均是宏,在这里取形式上的,用函数一次来说吧。

在调用这几个函数之前,需要先声明一个变量,类型为va_list

2 va_start函数初始化声明或的valast参数为形参中最后一个类型已知的参数,目前来看也就是const char* fmt这个参数(fmt是一个形参名),是一个(格式)字符串。

  va_arg函数就是用来详细解释可变参数的,遍历格式字符串,返回对应类型的值

      Va_end函数与va_start函数呼应,end之后va_list的值就是未定义的了。

      Va_copy函数将src复制给dest,所以dest也需要va_end函数,这个函数时C99添加的,添加原因与不同的系统实现有关,man手册中有例子,可以查看。

注:这些宏与旧版的varargs.h中的不兼容

 

下面是官方给出的一个关于va_args函数的例子

               #include 

       #include 

 

       void

       foo(char *fmt, ...)

       {

           va_list ap;

           int d;

           char c, *s;

 

           va_start(ap, fmt);

           while (*fmt)

               switch (*fmt++) {

               case 's':              /* string */

                   s = va_arg(ap, char *);

                   printf("string %s\n", s);

                   break;

               case 'd':              /* int */

                   d = va_arg(ap, int);

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

                   break;

               case 'c':              /* char */

                   /* need a cast here since va_arg only

                      takes fully promoted types */

                   c = (char) va_arg(ap, int);

                   printf("char %c\n", c);

                   break;

               }

           va_end(ap);

      }

如果想要直接打印或者使用这些可变参,stdargs提供了几个专用的函数,直接使用printf之类的会出现意想不到的错误哦。

 #include 

 

 int vprintf(const char *format, va_list ap);

 int vfprintf(FILE *stream, const char *format, va_list ap);

 int vsprintf(char *str, const char *format, va_list ap);

 int vsnprintf(char *str, size_t size, const char *format, va_list ap);

 

看看最后两个参数的类型,果然是量身定做吧。

 

----------------------- -------------------   我是 引用 分隔线 -------------------- ------------------ ---

 

既然说了可变参的函数,就也说下可变宏吧,挺常用的,下面的就写的挺好的,借来用感谢原作者。

 

般在调试打印Debug信息的时候需要可变参数的宏C99开始可以使编译器标准支持可变参数宏(variadic macros), 另外GCC也支持可变参数宏但是两种在细节上可能存在区别.

 

(1). __VA_ARGS__

__VA_ARGS__ 将 "..." 传递给宏 

#define debug(format, ...) fprintf(stderr, format, __VA_ARGS__)

 

(2). GCC的复杂宏

GCC使用一种不同的语法,从而可以给可变参数一个名字,如同其它参数一样.

#define debug(format, args...) fprintf (stderr, format, args)

这和第一条的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述.

 

(3). ##__VA_ARGS__

上面两个定义的宏,如果出现 debug("A Message")的时候,由于宏展开后有个多余的逗号,所以将导致编译错误.

为了解决这个问题,CPP 使用一个特殊的"##"操作,格式如下:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,"##"操作将使预处理器(preprocessor)去除掉它前面的那个逗号.

 

你可能感兴趣的:(IT相关)