变长参数的 Tracer

系统 1721 0

几天前,在CSDN论坛看到这么一则讨论: 在宏定义中怎么使用可变参数? ( http://expert.csdn.net/Expert/topic/2925/2925165.xml )。楼主希望能定义这样的macro:

#define fun1(a, b, ...)   fun2(__FILE__, __LINE__, a, b, ...)

我猜楼主是想写trace,如果不能使用可变参数的macro,那么就得像MFC那样写一堆TRACE macros:


// 取自 MFC 7.1 的 afx.h
// The following trace macros are provided for backward compatiblity
//  (they also take a fixed number of parameters which provides
//   some amount of extra error checking)
#define TRACE0(sz)               TRACE(_T("%s"), _T(sz))
#define TRACE1(sz, p1)           TRACE(_T(sz), p1)
#define TRACE2(sz, p1, p2)       TRACE(_T(sz), p1, p2)
#define TRACE3(sz, p1, p2, p3)   TRACE(_T(sz), p1, p2, p3)

太丑陋了!还好,C99标准支持Variadic Macros,在GCC中,可以这么写:

// http://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html
#define debug(format, ...)  fprintf(stderr, format, __VA_ARGS__)

还可以顺便打印文件名和行号:

#define debug(format, ...)  do {\
                fprintf(stderr, "%s (%d): ", __FILE__, __LINE__);\
                fprintf(stderr, format, __VA_ARGS__);\
                } while (0)

但可惜Visual C++ 7.1还不支持这项功能:( 不过我们在C++中至少可以绕弯解决,做到 既能自动记录文件名和行号,又能使用变长参数调用 。这个办法不是我独创的,实际上ATL的 atltrace.h 中就有它的实现( CtraceFileAndLineInfo class),我在Code Project也找到了相同的实现( http://www.codeproject.com/debug/location_trace.asp ),甚至在CUJ的C++ Experts Forum 也能看到相近的做法( http://www.cuj.com/documents/s=8250/cujcexp2106alexandr/ ),当然Alexandrescu的办法技巧性更强。

思路:写一个重载了 operator() 的class,令 TRACE 宏返回该class的一个object:

#include
#include

#ifndef NDEBUG  // debug mode

class tracer
{
public:
  tracer(const char* file, int line)
    : file_(file), line_(line)
  {}
 
  void operator() ( const char* fmt, ... )
  {
    va_list ap;
   
    // print the file name and line number
    fprintf(stderr, "%s (%d): ", file_, line_);
   
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
   
    fprintf(stderr, "\r\n"); // print the new-line character
  }

private:
  // copy-ctor and operator=
  tracer(const tracer&);
  tracer& operator=(const tracer&);

private:
  const char* file_;
  int         line_;
};
#define TRACE (tracer(__FILE__, __LINE__))
#else  // NDEBUG
#define TRACE (void)
#endif // NDEBUG

int main()
{
#ifndef NDEBUG
  tracer(__FILE__, __LINE__)("%x", 123);
#endif

  TRACE("%s", "Happy debugging.");
}

这样做是multithreading-safe的。G++ 3.3.1 / Visual C++ 7.1 / Borland C++ 5.5.1 通过。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=565


变长参数的 Tracer


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论