编译器:假设条件总是真/假

Compiler: What if condition is always true / false

本文关键字:假设 条件 编译器      更新时间:2023-10-16

我想到了条件语句和编译器。我正在为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。但我想知道我是否应该重写它,或者它是否会浪费时间。

任何半成品的优化编译器都会删除if语句中的整个代码,前提是它可以在编译时告知条件总是计算为false。类似地,如果条件总是真的,任何半成品编译器都会跳过检查本身。

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

#define DEBUG

#ifdef DEBUG
...
#endif

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

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

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

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

  • 预处理器条件
  • 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
}

我不喜欢回答我自己的问题,因为如果没有你们的帮助,我不会解决的,伙计们。

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

#if DEBUG == true
#endif

#ifdef DEBUG
#endif

编译器没有在#if/#ifdef中获得代码(预处理器将其删除(,因此,如果这部分代码中存在问题,如果DEBUG设置为false或根本没有定义,则没有人会知道这一点(谢谢@Klaus(。

第二种选择:

#define DEBUG false    
...
if (DEBUG)
{
  ...
}

如果条件为false,则任何较新的编译器都应删除"if"块;如果条件为true,则应删除"if"语句并保留正文。

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

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

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

如果你喜欢这个答案,投赞成票,我会接受的——如果没有人提供更好的答案。