C ++函数调用标识符

时间:2009-07-10 07:27:48

标签: c++ c-preprocessor

请考虑以下代码:

void Foo() {
  ......
  LOG_ERROR("I'm error 1")   // call 1
  .....
  LOG_ERROR("I'm error 2")  // call 2
  .....

}

LOG_ERROR()是一个宏。 LOG_ERROR()应该打印识别它的字符串 在代码中,虽然假设代码可以改变,但是A::Foo() 将保持不变。标识符应保留在代码中 变化。

这可以通过将错误代码添加为LOG_ERROR()的参数来解决, 但我们希望从程序员中删除管理错误的负担 码。

使用__LINE__不是答案,因为Foo()可以从构建移动到 建立。

因此,我考虑过相对于开始时识别LOG_ERROR() Foo()

  • 一个。按文件名(__FILE__)+函数名称(__FUNCTION__)+标识 LOG_ERROR()相对于Foo()的行号开始。
  • 湾按文件名(__FILE__)+函数名称(__FUNCTION__)+标识 LOG_ERROR()中的Foo()来电号码。

解决方案至少应该适用于VC ++ 2008和g ++ 4.1.1。

一个建议的解决方案(link text)是:

#define ENABLE_LOG_ERROR static const int LOG_ERROR_start_line = __LINE__
#define LOG_ERROR(s) cerr << "error #" << (__LINE__ - LOG_ERROR_start_line) \
    << " in " << __func__ << ": " << s << endl

void Foo() {
     ENABLE_LOG_ERROR;
     //...
     LOG_ERROR("error 1");
     int i;
     LOG_ERROR("error 2");
} 

这将强制用户在每个包含的函数的开头写入ENABLE_LOG_ERROR LOG_ERROR()并且有很多这样的功能。

还有其他方法可以完成任务吗?

3 个答案:

答案 0 :(得分:1)

此解决方案非标准,但MSVC和GCC都支持__COUNTER__,每次调用时都会递增。

#define LOG_ERROR(s) cerr << "error #" << (__COUNTER__) << " in " \
<< __func__ << ": " << s << endl

请注意,__COUNTER__将在每个编译单元中重置,并且仅在每个编译单元中重置。因此,如果Foo()有7个LOG_ERROR()个宏,则在稍后的函数Bar()中,__COUNTER__的值在LOG_ERROR()的第一次使用时将为7。

答案 1 :(得分:1)

虽然问题是如何在函数中生成唯一行标识符以进行日志记录,但我将退后一步,查看要解决的实际问题:如何生成可以轻松识别的日志输出源代码行,而不会给代码的编写者带来负担。

假设您在程序的每个版本中嵌入了一个唯一的构建版本(这通常是一个好主意)。我们还假设您正在使用源代码控制机制来保存源代码的历史记录(无论如何这也是一个非常好的主意)并且可以向您提供源代码,因为它可以用于任何请求的构建版本的源代码。程序

如果这些假设成立,那么解决方案是让您的程序将其当前版本写入日志文件。然后,每个单独的日志记录条目只需通过__LINE__记录行号。

因此,当有人需要使用日志时:他们可以查看日志中的版本号,从源代码控制存储库中获取相应的源,并使用日志中的行号转到正确的源代码行。这给使用日志输出的人带来了更多负担。但是,如果记录的代码依赖于或受其他可能因版本而异的代码的影响,那么无论如何都可能需要源代码的历史状态。

此外,以这种方式工作的好处是,它需要假设任何给定的函数将保持不变,这是最初的问题的一部分。所以这种方法有更广泛的应用。


就实现而言,您可以在程序启动时记录程序版本,也可以让记录宏在每个条目中包含它。

如果程序版本通常存储在普通源代码中不易访问的地方,那么您可以创建一个预构建步骤,该步骤将提取版本并将其作为#define或const字符串写入简单的version.h文件中。然后日志代码或宏可以自动使用它来始终输出当前版本的程序。

答案 2 :(得分:0)

通过修改堆栈的想法,使用从std::map到计数的std::string映射,并查找函数名称。

std::map<std::string, int> LOG_ERROR_count_map;
#define LOG_ERROR(s) {\
  int count = ++LOG_ERROR_count_map[ __func__ ];\
  std::cout << count << " in " __func__ ": " s << std::endl;\
}

这意味着您不需要ENABLE_LOG_ERROR,但代价是每个日志的地图查找。 (这是易用性和时间之间的权衡。)