C++ 技术中心

   :: 首页 :: 联系 ::  :: 管理
  150 Posts :: 0 Stories :: 83 Comments :: 0 Trackbacks

公告

郑重声明:本BLOG所发表的原创文章,作者保留一切权利。必须经过作者本人同意后方可转载,并注名作者(天空)和出处(CppBlog.com)。作者Email:6549168@qq.com

留言簿(5)

搜索

  •  

最新随笔

最新评论

评论排行榜

60天内阅读排行

几天前,在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 通过。

posted on 2013-08-19 11:03 C++技术中心 阅读(1381) 评论(1)  编辑 收藏 引用 所属分类: C++ 基础

Feedback

# re: 可变参数[未登录] 2013-08-20 13:05 xu
此tracer的设计确实十分精妙!  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理