【发布时间】:2009-09-07 13:54:56
【问题描述】:
可以使用#define printf 删除对printf() 的所有调用。如果我有很多像 std::cout << x << endl; 这样的调试打印怎么办?如何使用预处理器快速关闭单个文件中的cout << 语句?
【问题讨论】:
标签: c++ c-preprocessor cout
可以使用#define printf 删除对printf() 的所有调用。如果我有很多像 std::cout << x << endl; 这样的调试打印怎么办?如何使用预处理器快速关闭单个文件中的cout << 语句?
【问题讨论】:
标签: c++ c-preprocessor cout
正如“放松”已经说过的那样,快速解决方案是无所事事的流。不过有更好的实现:
class NullStream {
public:
NullStream() { }
template<typename T> NullStream& operator<<(T const&) { return *this; }
};
您仍然对std::cout 有一点问题,因为这是三个标记的序列,您真的不想单独重新定义std 或cout。一个简单的解决方案是
#ifdef NDEBUG
#define COUT std::cout
#else
#define COUT NullStream()
#endif
COUT << "Hello, world" << std::endl;
【讨论】:
作为一般原则,应避免记录到标准输出 - 最好记录到日志文件,然后您可以使用标准配置工具更改日志级别,或完全关闭它。
只要我的 0.02 美元.....
【讨论】:
用以下内容替换您的调试输出语句:
IFDBG(cout << result << endl);
然后你可以相应地定义宏:
#ifdef DEBUG
# define IFDBG(x) x
#else
# define IFDBG(x)
#endif
【讨论】:
IFDBG(cout << foo(x,y) << std::endl);。逗号会破坏宏。
如果您正在寻找可以快速删除调试语句的东西,NullStream 可能是一个很好的解决方案。不过,我建议您创建自己的调试类,当需要更多调试功能时,可以根据需要对其进行扩展:
class MyDebug
{
std::ostream & stream;
public:
MyDebug(std::ostream & s) : stream(s) {}
#ifdef NDEBUG
template<typename T>
MyDebug & operator<<(T& item)
{
stream << item;
return *this;
}
#else
template<typename T>
MyDebug & operator<<(T&)
{
return *this;
}
#endif
};
这是一个简单的设置,可以做你最初想做的事情,而且它还有一个额外的好处,可以让你添加调试级别等功能。
更新: 现在由于操纵器是作为函数实现的,如果你也想接受操纵器(endl),你可以添加:
MyDebug & operator<<(std::ostream & (*pf)(std::ostream&))
{
stream << pf;
return *this;
}
对于所有操纵器类型(这样您就不必为所有操纵器类型重载):
template<typename R, typename P>
MyDebug & operator<<(R & (*pf)(P &))
{
stream << pf;
return *this;
}
小心最后一个,因为它也会接受常规函数指针。
【讨论】:
定义这个宏:
#ifdef DEBUG
#define MY_LOG std::cout
#else
#define MY_LOG if(false) std::cout
#endif
这个宏的优势在于编译器优化
如果放置在这些 IF 中的表达式在编译时是常量且可确定,那么您几乎可以肯定编译器已经为您从代码中删除了它们... https://stackoverflow.com/a/14657645/5052296
【讨论】:
您可能可以使用一个名为cerr 的实例来定义一个新的类流类的预处理器hack,它什么都不做。如果你真的很幸运,编译器会看到该函数什么都不做,并优化对operator<<() 的调用。
类似
class NullStream
{
public:
NullStream();
NullStream& operator<<(const std::string& text) { return *this; }
// And operators for other types, too
}
static NullStream cerr;
不过,这确实是个 hack,最好是(远)浏览您的源代码并添加对日志记录的适当支持。
【讨论】:
定义一个替换 cout 的宏不是您应该上传到 VCS 的内容,但如果您只是在调试期间临时这样做,我认为它可以发挥作用。所以你可以把cout替换成ostream(0)就好了
#ifdef NDEBUG
#define cout ostream(0).flush()
#endif
这样,它可以与std::cout 和普通cout 一起使用,并且ostream 在包含<iostream> 时可用。写入ostream(0) 是无操作的。 flush 函数调用已完成,以便您获得对它的非常量引用(因此它还绑定到用于输出 std::string 和其他的非成员 operator<<)。因为它的类型是ostream,它的行为应该和cout完全一样。
【讨论】: