变长参数的 Tracer

2024-01-19 23:58
文章标签 参数 tracer

本文主要是介绍变长参数的 Tracer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

这篇关于变长参数的 Tracer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/624136

相关文章

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

MySQL中时区参数time_zone解读

《MySQL中时区参数time_zone解读》MySQL时区参数time_zone用于控制系统函数和字段的DEFAULTCURRENT_TIMESTAMP属性,修改时区可能会影响timestamp类型... 目录前言1.时区参数影响2.如何设置3.字段类型选择总结前言mysql 时区参数 time_zon

Python如何使用seleniumwire接管Chrome查看控制台中参数

《Python如何使用seleniumwire接管Chrome查看控制台中参数》文章介绍了如何使用Python的seleniumwire库来接管Chrome浏览器,并通过控制台查看接口参数,本文给大家... 1、cmd打开控制台,启动谷歌并制定端口号,找不到文件的加环境变量chrome.exe --rem

Linux中Curl参数详解实践应用

《Linux中Curl参数详解实践应用》在现代网络开发和运维工作中,curl命令是一个不可或缺的工具,它是一个利用URL语法在命令行下工作的文件传输工具,支持多种协议,如HTTP、HTTPS、FTP等... 目录引言一、基础请求参数1. -X 或 --request2. -d 或 --data3. -H 或

详解Spring Boot接收参数的19种方式

《详解SpringBoot接收参数的19种方式》SpringBoot提供了多种注解来接收不同类型的参数,本文给大家介绍SpringBoot接收参数的19种方式,感兴趣的朋友跟随小编一起看看吧... 目录SpringBoot接受参数相关@PathVariable注解@RequestHeader注解@Reque

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

spring 参数校验Validation示例详解

《spring参数校验Validation示例详解》Spring提供了Validation工具类来实现对客户端传来的请求参数的有效校验,本文给大家介绍spring参数校验Validation示例详... 目录前言一、Validation常见的校验注解二、Validation的简单应用三、分组校验四、自定义校

SpringBoot中Get请求和POST请求接收参数示例详解

《SpringBoot中Get请求和POST请求接收参数示例详解》文章详细介绍了SpringBoot中Get请求和POST请求的参数接收方式,包括方法形参接收参数、实体类接收参数、HttpServle... 目录1、Get请求1.1 方法形参接收参数 这种方式一般适用参数比较少的情况,并且前后端参数名称必须