【问题标题】:Advantages of conditional-preprocessor over conditional statements条件预处理器相对于条件语句的优势
【发布时间】:2013-06-05 03:02:17
【问题描述】:

我从未与 #if#ifdef#ifndef#else 合作过>#elif#endif

当我浏览一些源代码时,我发现了这些指令的广泛使用。 对条件预处理器进行了一些阅读,但没有发现它们与普通条件语句有何不同之类的线索。 所以我想知道下面的代码有什么好处:

#include<iostream>
int main()
{
    int i = 0;

    #if i == 0
         std::cout<<"This";
    #else
         std::cout<<"That";
    #endif
    return 0;
}

在此:

#include<iostream>
int main()
{
    int i = 0;

    if (i == 0)
         std::cout<<"This";
    else
         std::cout<<"That";
    return 0;
}

另外,什么时候使用/不使用条件预处理器?

【问题讨论】:

  • 对于初学者,if 在运行时评估,#if 在编译时评估。
  • @xaxxon:您能解释一下该链接的相关性吗?
  • 在这种(以及许多)情况下,如果您在编译器中打开优化,它们将给出相同的二进制结果。但是,您的第一个示例存在语法问题,因为 #if 不能与常规变量一起使用。
  • @xaxxon 我没看到。该问题询问何时应该使用哪一个,但这是一个完全合法、可以回答的问题,而不是一个讨论的开始。
  • 你的代码不是 C,C++ 社区可能对这个问题有不同的感受。

标签: c++ c-preprocessor preprocessor-directive


【解决方案1】:

条件预处理器不像您的第一个示例那样工作。

它使用常量,你明白吗?在编译时,它会查看各种条件,并根据它放入/省略源代码。

例如:

#define HAS_COMPARISON

int main() {
    #ifdef HAS_COMPARISON
        int i = 0;
        if(i == 0) std::cout << "This";
        else
    #else
        std::cout << "That";
    #endif
}

设置define,它将设置变量i并执行比较...简而言之,它将输出This。如果您对该定义进行注释,则整个块将不在您的程序中,这意味着它将始终输出That,而无需设置变量或进行比较。

这是预处理器定义最常见的用途。您还可以定义值并将其与具有相同定义的变量行为进行比较,但这是另一个问题。

再一次:条件预处理器在编译时评估,变量条件在运行时评估。

【讨论】:

  • ~ 如果我错了,请纠正我,如果在编译前将 HAS_COMPARISON 设置为 0,那么编译器会消除 #else中的块> & #endif 就像 dead code 消除 一样。
  • @iKishore 预处理器会在编译器看到它之前删除代码,这很重要,因为条件化的代码在编译器看到它时可能无法编译/导致错误(例如由于类型错误或缺少功能)。
  • @iKishore 不,你是对的。如果它设置为 ANY 值,#else 将被删除,而如果 #define 从代码中删除,则从 #ifdef#else 的所有内容都将被删除。
【解决方案2】:

由于缺少其他信息,您展示的示例似乎没有帮助。但这里有一个#if 很有用的例子。

#if OS == LINUX
//do something
#elif OS == SOLARIS
//do something else
#else
//
#endif

关键是#if是在编译时求值的,而if是在程序运行时求值的。

#if BYTE_ORDER == LITTLE_ENDIAN
//do something
#else
//do something else
#endif

【讨论】:

    【解决方案3】:

    在这种情况下使用预处理器指令并不完全有用。但是这些预处理器指令的使用在许多其他情况下很有用。

    这些预处理器指令可用于条件编译。例如如果必须为多个平台开发某些程序,则可以为特定于平台的常量指定值。更改特定于平台的这些值编译可以完成,同时整个代码可以作为一个大实体进行维护。

    这些在调试时也很有用。测试单元可以编译到代码中并在调试时使用这些条件编译运行,并且可以使用它们停止编译。

    【讨论】:

      【解决方案4】:

      条件编译意味着 ifdef 输出的代码实际上永远不会出现在最终链接的应用程序中。仅使用语言条件意味着两个分支都在最终代码中,这使得它变得更大并且可能更难测试等。

      当您在编译时知道需要什么时,使用#ifdef 等。当您直到运行时才知道自己需要什么时,就会使用语言条件。

      【讨论】:

        【解决方案5】:

        预处理器的好处是代码会被丢弃。它不会被编译(这需要时间),也不会生成将加载到 ram 中的机器代码。如果决策是在一个非常紧凑的循环中运行很多次,那么速度可能会有所提高。但是,除非您实际计时,否则不要认为这很重要。

        预处理器的缺点是您显然必须在编译时知道答案。源代码现在包含许多可能永远不会执行的代码。追踪人类变得更加困难,因为通常很难确定那些编译时值是什么。

        【讨论】:

        • 实际上,如果条件是编译时常量(并且足够简单,预处理器是一个选项),如果使用if 进行测试,编译器通常能够推断出并删除死代码.
        • 确实如此。记住编译器有多聪明总是好的。人们经常编写令人困惑的代码来尝试进行一些过早的优化,然后意识到他们并没有让它变得更快,而且更难阅读/维护。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-31
        • 1970-01-01
        • 1970-01-01
        • 2010-09-07
        • 1970-01-01
        • 2018-10-22
        相关资源
        最近更新 更多