请考虑以下代码:
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()
并且有很多这样的功能。
还有其他方法可以完成任务吗?
答案 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
,但代价是每个日志的地图查找。 (这是易用性和时间之间的权衡。)