可变参数宏

来源:互联网 发布:国家 大数据 宣传片 编辑:程序博客网 时间:2024/04/27 05:00
 
带有可变参数的宏(Macros   with   a   Variable   Number   of   Arguments  
   
 
1999年版本的ISO   C   标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:  
   
  #define   debug(format,   ...)   fprintf   (stderr,   format,   __VA_ARGS__)  
   
 
这里,‘…’指可变参数。这类宏在被调用时,它(这里指‘…’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro   body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。  
   
  GCC
始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:  
   
  #define   debug(format,   args...)   fprintf   (stderr,   format,   args)  
   
 
这和上面举的那个ISO   C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。  
   
  GNU   CPP
还有两种更复杂的宏扩展,支持上面两种格式的定义格式。  
   
 
在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO   C里是非法的,因为字符串后面没有逗号:  
   
  debug   ("A   message")  
   
  GNU   CPP
在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。  
   
 
为了解决这个问题,CPP使用一个特殊的‘##’操作。书写格式为:  
   
  #define   debug(format,   ...)   fprintf   (stderr,   format,   ##   __VA_ARGS__)  
   
 
这里,如果可变参数被忽略或为空,‘##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU   CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted   macro参数一样,这些参数不是宏的扩展。
 
 
可变参数宏的一种实现:(Macros   with   a   Variable   Number   of   Arguments  
   
   
 
C99中,宏可以象函数一样,带有可变参数。宏的语法和函数的语法类似。下面有个例子:  
   
  #define   debug(format,   ...)   fprintf   (stderr,   format,   __VA_ARGS__)  
   
 
但是现在就我所知道的情况,还没有哪个编译器支持C99标准,所以上面的代码其实只是人们玩的空手道。  
   
  GCC
编译器对宏定义有一种扩展,可以实现类似于可变参数宏的机制。例如:  
   
  #define   debug(format,   args...)   fprintf   (stderr,   format,   args)  
   
 
这里所要讨论的是Win32,或者说就是Visual   C++下面可变参数红的一种实现。  
   
 
其实可变参数宏主要是应用在程序输出调试信息,我们都知道,在MFC下有个非常有名的AfxTrace宏,它就是用来输出调试信息的,下面是MFC   7.0  
 
TRACE宏的定义:  
   
  void   AFX_CDECL   AfxTrace(LPCTSTR   lpszFormat,   ...)  
  {  
    va_list   args;  
    va_start(args,   lpszFormat);  
   
    int   nBuf;  
    TCHAR   szBuffer[512];  
   
    nBuf   =   _vsntprintf(szBuffer,   _countof(szBuffer),   lpszFormat,   args);  
   
    //   was   there   an   error?   was   the   expanded   string   too   long?  
    ASSERT(nBuf   >=   0);  
   
    afxDump   <<   szBuffer;  
   
    va_end(args);  
  }  
   
 
其实我们也可以按照这样一种写法实现自己的可变参数宏,下面是示例代码:  
   
  #include   <stdarg.h>  
  #include   <wtypes.h>  
   
  void   __cdecl   db_print(const   char   *lpszFormat,...)  
  {  
    int   nBuf;  
    char   szBuffer[512];  
    va_list   args;  
    va_start(args,lpszFormat);  
   
    nBuf   =   _vsnprintf(szBuffer,   sizeof(szBuffer),   lpszFormat,   args);  
   
   
    printf("%s",szBuffer);  
    va_end(args);  
  }  
   
  #define   Debug_print   db_print  
   
  int   main()  
  {  
    char   *s1="hello";  
    char   *s2="world";  
    Debug_print("
调试信息:   %s/n",s1);  
    Debug_print("
调试信息:   %s/n",s2);  
    Debug_print("
调试信息:   %s,%s",s1,s2);  
    return   0;  
  }    
 
 
原创粉丝点击