仅在调试模式下的控制台输出 c++
Console output only in debug mode c++
我本以为这会是一个被广泛问到的问题,但我仍然没有找到答案。
我正在调试一些 C++ 代码,这些代码仅在将某些函数句柄作为输入时以微妙的方式产生错误。长话短说解决了问题,但我在 .cpp 文件中定义:
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
不用说代码中到处都是:
DEBUG("Foo's address")
DEBUG(&Foo)
现在我假设在 "Release" 中编译器将忽略所有这些预编译器输出。但事实并非如此!
那么在实践中如何做到这一点(我想保留输出以供将来添加,但显然不希望在发布版本中使用)?我正在尝试使用 cmake 的 clion,这是 IDE/compiler 特定的吗?
谢谢
根据你的编译器,它可能会定义一些东西告诉你编译处于调试模式(或者你可以在命令行上自己做),然后:
#ifndef _DEBUG // works in VS
#define DEBUG(x)
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif
有关使用哪个宏的更多讨论,请参阅 this 问题。
执行此操作的便携式方法是使用 NDEBUG
#ifdef NDEBUG
#define DEBUG(x)
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif
参见:C / C++ : Portable way to detect debug / release?
在所谓的 "release versions" 中消除日志消息通常是错误的。毕竟,"release versions" 是您最需要记录信息的地方!当最终用户只会告诉您 "it doesn't work" 或“它崩溃了 时,您还希望如何分析和解决问题? "?
因此,与其消除您的软件为帮助您修复错误而创建的有价值的信息,不如考虑如何保存和保留这些信息,以便在出现问题时最终用户可以轻松地将其传输给您。例如,当应用程序在用户机器上运行时,将日志消息重定向到日志文件(也许应用程序本身提供 "Send log file to support" 功能,或类似的东西)。
代码类似
DEBUG("Foo's address")
DEBUG(&Foo)
应替换为:
Log("Foo's address");
Log(std::to_string(&Foo));
然后在你的 Log
函数中,它可能有一个像 void Log(std::string const& message)
这样的签名,你可以检查你的 DEBUG
宏并采取相应的行动:
void Log(std::string const& message)
{
#ifdef DEBUG
// write message to std::cerr
#else
// write message to log file
#endif
}
现在,DEBUG
当然 不是标准宏 (与 NDEBUG
不同,后者会打开和关闭 assert
)。它不是隐式定义的。您必须在调用编译器时自己定义它。例如,/DDEBUG
与 MSVC 或 -DDEBUG
与 GCC。有可能你的 IDE 在运行编译器时添加了这样一个标志,或者类似 -D_DEBUG
的东西,但这仍然不是标准的,也不是编译器本身的一部分。 (实际上,如果您要像这样使用它,您可能会考虑为宏起一个不同的名称,例如 LOG_TO_CONSOLE
。)
无论如何,这只是为了让您了解如何做。您可能更喜欢基于 std::ostream
的方法,而不是采用 std::string
的函数。 Whosebug上有很多关于这个的问答。
重要的一点是:不要假设一旦您的软件发布就不需要它,就不要丢弃有价值的日志信息。会有bug和模糊的错误描述。
我本以为这会是一个被广泛问到的问题,但我仍然没有找到答案。
我正在调试一些 C++ 代码,这些代码仅在将某些函数句柄作为输入时以微妙的方式产生错误。长话短说解决了问题,但我在 .cpp 文件中定义:
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
不用说代码中到处都是:
DEBUG("Foo's address")
DEBUG(&Foo)
现在我假设在 "Release" 中编译器将忽略所有这些预编译器输出。但事实并非如此!
那么在实践中如何做到这一点(我想保留输出以供将来添加,但显然不希望在发布版本中使用)?我正在尝试使用 cmake 的 clion,这是 IDE/compiler 特定的吗?
谢谢
根据你的编译器,它可能会定义一些东西告诉你编译处于调试模式(或者你可以在命令行上自己做),然后:
#ifndef _DEBUG // works in VS
#define DEBUG(x)
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif
有关使用哪个宏的更多讨论,请参阅 this 问题。
执行此操作的便携式方法是使用 NDEBUG
#ifdef NDEBUG
#define DEBUG(x)
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif
参见:C / C++ : Portable way to detect debug / release?
在所谓的 "release versions" 中消除日志消息通常是错误的。毕竟,"release versions" 是您最需要记录信息的地方!当最终用户只会告诉您 "it doesn't work" 或“它崩溃了 时,您还希望如何分析和解决问题? "?
因此,与其消除您的软件为帮助您修复错误而创建的有价值的信息,不如考虑如何保存和保留这些信息,以便在出现问题时最终用户可以轻松地将其传输给您。例如,当应用程序在用户机器上运行时,将日志消息重定向到日志文件(也许应用程序本身提供 "Send log file to support" 功能,或类似的东西)。
代码类似
DEBUG("Foo's address") DEBUG(&Foo)
应替换为:
Log("Foo's address");
Log(std::to_string(&Foo));
然后在你的 Log
函数中,它可能有一个像 void Log(std::string const& message)
这样的签名,你可以检查你的 DEBUG
宏并采取相应的行动:
void Log(std::string const& message)
{
#ifdef DEBUG
// write message to std::cerr
#else
// write message to log file
#endif
}
现在,DEBUG
当然 不是标准宏 (与 NDEBUG
不同,后者会打开和关闭 assert
)。它不是隐式定义的。您必须在调用编译器时自己定义它。例如,/DDEBUG
与 MSVC 或 -DDEBUG
与 GCC。有可能你的 IDE 在运行编译器时添加了这样一个标志,或者类似 -D_DEBUG
的东西,但这仍然不是标准的,也不是编译器本身的一部分。 (实际上,如果您要像这样使用它,您可能会考虑为宏起一个不同的名称,例如 LOG_TO_CONSOLE
。)
无论如何,这只是为了让您了解如何做。您可能更喜欢基于 std::ostream
的方法,而不是采用 std::string
的函数。 Whosebug上有很多关于这个的问答。
重要的一点是:不要假设一旦您的软件发布就不需要它,就不要丢弃有价值的日志信息。会有bug和模糊的错误描述。