条件始终为真/假的 if 语句的编译器优化

问题描述 投票:0回答:3

我想到了条件和编译器。我正在为 Arduino 编写一个应用程序,因此我需要该应用程序尽可能快。

在我的代码中我有这个:

#define DEBUG false    

...

if (DEBUG)
{
  String pinName;
  pinName = "Pin ";
  pinName += pin;
  pinName += " initialized";
  Serial.println(pinName);
}

我想知道编译器是否不将代码(if 块中的代码)包含在二进制文件中。条件总是假的,所以程序永远不会去那里。

从另一边来看。如果 DEBUG 为真怎么办? Arduino 是否测试条件或编译器仅在二进制文件中包含 if 的主体?

我找到了这个网站https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_4.html关于#if指令,所以我可以重写代码以使用这些指令而不是“正常”if。但我想知道我是否应该重写它,或者这是否会浪费时间。

c++ if-statement gcc compiler-optimization
3个回答
10
投票

任何半像样的优化编译器都会删除 if 语句内的整个代码,如果它可以在编译时告知条件始终评估为 false。类似地,如果条件始终为真,任何半正经的编译器都会跳过检查本身。

事实上,这完全等同于“编译器开关”,例如:

#define DEBUG


#ifdef DEBUG
...
#endif

带有

#ifdef
的“编译器切换”语法是首选,因为它使其他 C 程序员的意图更清晰。但这只是编码风格的问题 - 它将产生与原始代码相同的二进制文件。


2
投票

您编写的代码永远不应该被执行,但是,它可以在可执行文件中使用。

我想说,当您禁用优化时(例如将

-O0
添加到 Clang 和 GCC),编译器将需要保留此代码。 在所有其他情况下,我希望编译器删除代码,因为这是一个非常简单的优化,具有显着的代码大小效果。例如,GCC 在
-O
及更高级别消除了这一点。 (参见手册

不过,还有另外 2 种编写代码的方法,这将强制不包含此代码:

  • 预处理器条件
  • constexpr if

通过使用预处理器条件,您将能够在代码到达实际编译器之前将其删除。尽管它适用于 C 和 C++ 标准的所有编译器和版本,但它可能会对您的缩进产生一点干扰。

#ifdef DEBUG
   { // Optional: Adding extra scope to prevent usage of local variables after the endif
   // Code to eliminate
   }
#endif

但是,如果您使用的是 C++17,则还可以使用 constexpr if。这将减少对代码的干扰,尽管 if 语句中的代码必须语法正确,但它不必编译(因此语义上不正确)。

这可以写成:

if constexpr (DEBUG)
{
    // Code to eliminate
}

0
投票

我不喜欢回答我自己的问题,因为如果没有你们的帮助,我就无法解决这个问题。

无论如何,第一个选择是使用:

#if DEBUG == true
#endif

#ifdef DEBUG
#endif

编译器不会获取#if / #ifdef中的代码(预处理器将其删除),因此如果这部分代码有问题,如果DEBUG设置为false或未定义,则没有人会知道它完全没有(感谢@Klaus)。

第二个选项:

#define DEBUG false    

...

if (DEBUG)
{
  ...
}

如果条件为假,任何较新的编译器都应该删除“if”块,或者如果条件为真,则删除“if”语句并保留主体。

所以我想说,哪种方法更适合应用程序的需求取决于程序员。

如果您需要确保代码不会包含在二进制文件中,则第一种方法更好。

如果您希望编译器在每次编译程序时检查整个代码,则第二种方法更好。

如果您喜欢这个答案,请投票,我会接受它 - 如果没有人提供更好的答案。

© www.soinside.com 2019 - 2024. All rights reserved.