用空的实现替换“定义宏”

时间:2019-01-23 10:31:35

标签: c++ optimization

我通常使用#define宏来添加代码,这些代码在作为调试时间而不是作为发行版时将在此处。例如:

#ifdef NDEBUG
# define LOG(msg) (void)msg
#else
# define LOG(msg) MyDebugLogger(msg)
#endif

相反,我在考虑使用简单的函数,只是不提供发布方法的主体:

void MyDebugLogger(std::string const& msg);

在MyDebugLogger.cpp中:

void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
    std::clog << msg << "\n"; // Or whatever
#else
    (void)msg;
#endif
}

我希望编译器能够清除调用并在Release中增加额外费用。我对么? 出于某种原因,这会是一个不好的做法吗?

编辑:我的问题是:如果我像以前一样使用宏,我知道在发布模式下,可执行文件将变得更小,更快,因为所有代码都已删除。 如果使用该功能,会一样吗?正如编译器可能会理解的那样,该函数不执行任何操作,因此没有必要。 (或者它将增加一个额外的,甚至很小的调用空函数)

2 个答案:

答案 0 :(得分:1)

实际上,您将执行与宏相同的操作:

void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
    std::clog << msg << "\n"; // Or whatever
#endif
}

答案 1 :(得分:1)

您的示例应该进行一些调整。在当前版本中,编译器仅“看到”函数签名,并发出对其符号的调用,该符号稍后将通过链接器进行解析,因此它无法自行对其进行优化。 (链接时间优化可能会对此有所帮助,但这在很大程度上取决于您的设置,而动态链接将使此操作变得不可能)。所以也许尝试这样的事情 在标题中:

// Assuming you are using clang or gcc,
// but is required to not give an error by the standard and probably
// not even needed.
[[gnu::always_inline]] 
void MyDebugLogger(std::string const& msg [[maybe_unused]])
{
  #ifdef NDEBUG
    MyDebugLoggerImplementation(msg);
  #endif
}

然后在.cpp文件中实现它。这种方法的另一个好处是您 方法需要使用NDEBUG编译Logger,而此方法提供了客户端代码的选择。