有条件编译器相对于有条件语句的优势

9

我之前从未使用过#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;
}

此外,在IT技术中,何时使用/不使用条件预处理器?

1
首先,if 在运行时被评估,而#if在编译期间被评估。 - Aiias
4
你能解释一下那个链接与此有什么关系吗? - Blender
1
在这种情况(和许多其他情况)下,如果您在编译器中开启优化,它们将生成相同的二进制结果。不过,您的第一个示例存在语法问题,因为#if不能与常规变量一起使用。 - Joachim Isaksson
1
@xaxxon 我没有看到那个。问题是询问应该在什么情况下使用哪一个,但这是一个完全合法的、可回答的问题,而不是一个讨论的开端。 - user395760
2
你的代码不是C语言。C++社区可能对此问题有不同的看法。 - Jens Gustedt
显示剩余6条评论
5个回答

5

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

它是使用常量运行的,你知道吗?在编译时,它会查看各种条件,并根据条件放置/省略源代码。

例如:

#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_内部的块? - kishoredbn
@iKishore 预处理器在编译器处理代码之前会将其删除,这很重要,因为条件代码在编译器处理时可能无法编译/导致错误(例如由于类型错误或缺少函数)。 - user395760
1
@iKishore 不,你是正确的。如果它被设置为任何值,#else 就会被消除,而如果从代码中删除 #define,则从 #ifdef#else 的所有内容都将被消除。 - Refugnic Eternium

5

你展示的例子由于缺乏其他信息似乎不太有用。但是这里有一个使用 #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

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

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

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


1
条件编译意味着ifdef的代码实际上不会出现在最终链接的应用程序中。仅使用语言条件语句会使两个分支都出现在最终代码中,从而使其变得更大、可能更难测试等。
当您在编译时知道所需内容时,请使用#ifdef等。当您直到运行时才知道所需内容时,请使用语言条件语句。

1

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

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


实际上,如果条件是编译时常量(并且足够简单以至于预处理器是一个选项),编译器通常能够推断出来并删除死代码,如果它被测试使用 if - user395760
足够正确。记住编译器的智能总是有好处的。人们经常写令人困惑的代码,试图进行一些过早的优化,然后意识到他们并没有使其更快,而且更难以阅读/维护。 - xaxxon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接