我使用的一些系统没有我正在使用的日志库,这对于生产运行中经过良好测试的代码来说是可以的——日志库主要用于调试和测试。在我的主开发机器以及我经常运行实验的几台服务器上,存在日志记录库。但有时我需要将实验外包给另一台具有更多节点和核心的服务器,但该服务器没有日志库。
例如,该库(Google glog)提供以下宏函数:
LOG(INFO) << "Insert my message here.";
LOG(FATAL) << "Insert another message here.";
所以,我所做的定义如下:
#ifdef NOLOGGING
#define MYLOG(i,m) std::cerr << #i << ": " << m << "\n";
#else
#define MYLOG(i,m) LOG(i) << m ;
#endif
使用这些定义,我现在可以编写如下语句:
MYLOG(INFO, "My info message");
MYLOG(FATAL,"My fatal message");
如果使用标志 -DNOLOGGING
进行编译,最后两个语句将扩展为:
std::cerr << "INFO" << ": " << "My info message" << "\n";
std::cerr << "FATAL" << ": " << "My fatal message" << "\n";
如果-DNOLOGGING
编译时未使用标志,它们将扩展为:
LOG(INFO) << "My info message";
LOG(FATAL) << "My fatal message";
我上面描述的解决方案令人满意,但并不理想。
理想情况下,当我无法访问日志库时,类似 MYLOG(FATAL,"foo")
的语句将扩展到打印到 std::cerr
的语句; 但是,类似 MYLOG(INFO,"bar")
的语句会扩大到什么都没有。换句话说,当我无法使用日志库时,我想要像 MYLOG(INFO,"bar")
这样的语句被忽视。这个想法是我不太关心 INFO
的日志消息当我使用没有日志库的服务器时,严重性很严重,但我仍然希望看到 FATAL
的消息严重程度。
如果可能的话,如何仅使用预处理器指令来完成此操作?
最佳答案
我认为您不能仅使用预处理指令来完成此操作,因为预处理器并没有真正为您提供必要的机制来根据宏的参数来指导宏扩展。
也就是说,您可以实现一些稍微丑陋的黑客行为,但会起作用。考虑以下代码:
#include <iostream>
#define MYLOG_ERR 1
#define MYLOG_INFO 0
#define P(a,b) a##b
#define MYLOG(x,y) do { if (P(MYLOG_,x)) { std::cerr << y << std::endl; } } while (0)
int main(void)
{
MYLOG(ERR, "err");
MYLOG(INFO, "info");
}
这种方法依赖于编译器的优化器来识别一些常见的习惯用法,例如 do { ... } while (0)
和 if (0)
/if (1)
优化编译时已知条件。但是,我认为它会给你你想要的。
关于基于宏函数参数的 C++ 宏函数扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20064261/