C++性能、优化编译器、.cpp 中的空函数

发布于 2024-08-31 22:18:19 字数 659 浏览 3 评论 0原文

我有一个非常基本的类,将其命名为 Basic,用于更大项目中的几乎所有其他文件。在某些情况下,需要有调试输出,但在发布模式下,不应启用此输出并且应为 NOOP。

目前,标头中有一个定义,可根据设置打开或关闭宏。所以当关闭时,这绝对是一个 NOOP。我想知道,如果我有以下代码,编译器(MSVS / gcc)是否能够优化函数调用,以便它再次成为 NOOP。 (通过这样做,开关可以位于 .cpp 中,并且在编译/链接时间方面切换速度会快得多)。

--Header--
void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      printDebug(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#else
void printDebug(const Basic* p) {}
#endif

I've a very basic class, name it Basic, used in nearly all other files in a bigger project. In some cases, there needs to be debug output, but in release mode, this should not be enabled and be a NOOP.

Currently there is a define in the header, which switches a makro on or off, depending on the setting. So this is definetely a NOOP, when switched off. I'm wondering, if I have the following code, if a compiler (MSVS / gcc) is able to optimize out the function call, so that it is again a NOOP. (By doing that, the switch could be in the .cpp and switching will be much faster, compile/link time wise).

--Header--
void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      printDebug(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#else
void printDebug(const Basic* p) {}
#endif

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

流云如水 2024-09-07 22:18:19

与所有此类问题一样,答案是 - 如果这对您来说真的很重要,请尝试该方法并检查发出的汇编语言。

As with all questions like this, the answer is - if it really matters to you, try the approach and examine the emitted assembly language.

月依秋水 2024-09-07 22:18:19

如果编译器在编译时知道 printDebug 函数的实现,它可能会优化此代码。如果 printDebug 在另一个目标模块中,则可能只能通过链接器使用整个程序优化来优化。但测试这一点的唯一方法是读取编译器生成的汇编代码。
如果你已经有 PRINT_DEBUG 宏,你可以通过 TRACE 定义的方式扩展它:

#define PRINT_DEBUG    // optional
#ifdef PRINT_DEBUG
#define PRINT_DEBUG_CALL(p) printDebug(p)
#else
#define PRINT_DEBUG_CALL(p)
#endif


void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      PRINT_DEBUG_CALL(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#endif

Compiler possibly may optimize this code, if it knows printDebug function implementation at compilation time. If printDebug is in another object module, this possibly may be optimized only by linker, using the whole program optimization. But the only way to test this is to read compiler-generated Assembly code.
If you already have PRINT_DEBUG macro, you can extend it by the way as TRACE is defined:

#define PRINT_DEBUG    // optional
#ifdef PRINT_DEBUG
#define PRINT_DEBUG_CALL(p) printDebug(p)
#else
#define PRINT_DEBUG_CALL(p)
#endif


void printDebug(const Basic* p);

class Basic {
   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      PRINT_DEBUG_CALL(this);
   }
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
   // Lengthy debug print
}
#endif
ゃ人海孤独症 2024-09-07 22:18:19
#if PRINT_DEBUG
#define printDebug _real_print_debug
#else
#define printDebug(...)
#endif

这样,预处理器将在所有调试代码到达编译器之前将其删除。

#if PRINT_DEBUG
#define printDebug _real_print_debug
#else
#define printDebug(...)
#endif

This way the preprocessor will strip all debug code before it even gets to the compiler.

无人接听 2024-09-07 22:18:19

目前大多数优化都是在编译时完成的。一些编译器如 LLVM 能够在链接时进行优化。这是一个非常有趣的想法。我建议你看一下。

等待此类优化,你可以做的有以下几件事。定义一个宏,允许您根据是否定义了 DEBUG 来包含以下语句。

#ifdef DEBUG
#define IF_DEBUG (false) {} else
#else
#define IF_DEBUG 
#endif

您可以像这样使用它,

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      IF_DEBUG printDebug(this);
   }

这已经比

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
#if DEBUG
      printDebug(this);
#endif
   }

注意您可以像关键字一样使用它更具可读性

IF_DEBUG {
   printDebug(this);
   printDebug(thas);
}

Currently most of the optimizations are done at compile time. Some compilers as LLVM are able to optimize at link time. This is a really interesting idea. I suggest you to take a look at.

Waiting for these kind of optimization, what you can do is the following. Define a macro that let you include the following statement depending on whether DEBUG is defined or not.

#ifdef DEBUG
#define IF_DEBUG (false) {} else
#else
#define IF_DEBUG 
#endif

You can the use it like this

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
      IF_DEBUG printDebug(this);
   }

which is already much more readable than

   Basic() {
      simpleSetupCode;

      // this should be a NOOP in release, 
      // but constructor could be inlined
#if DEBUG
      printDebug(this);
#endif
   }

Note that you can use it as if it was a keyword

IF_DEBUG {
   printDebug(this);
   printDebug(thas);
}
春风十里 2024-09-07 22:18:19

呃,为什么不以不同的方式使用预处理器宏呢?

就在我的头顶上,类似这样的东西:

  #define DEBUG_TRACE(p)
  #ifdef PRINT_DEBUG
    printDebug(p);
  #else
    ;
  #endif

errm, why not use the pre-processor macro differently?

Just of the top of my head, something like:

  #define DEBUG_TRACE(p)
  #ifdef PRINT_DEBUG
    printDebug(p);
  #else
    ;
  #endif
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文