9

I have never worked with #if, #ifdef, #ifndef, #else, #elif and #endif.

As I was going through some source-codes, I found an extensive use of these directives. Did some reading on conditional-preprocessors but found no clue like how are they different from normal conditional statements. So I was wondering what is the advantage of following code:

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

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

over this:

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

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

Also, when to-use/not-to-use conditional-preprocessor?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kishoredbn
  • 2,007
  • 4
  • 28
  • 47
  • 1
    For starters, `if` is evaluated at run-time and `#if` is evaluated before compile-time. – Aiias Jun 09 '13 at 07:02
  • http://stackoverflow.com/help/dont-ask – xaxxon Jun 09 '13 at 07:02
  • 4
    @xaxxon: Can you explain how that link is relevant? – Blender Jun 09 '13 at 07:03
  • @Blender sure. `I would like to participate in a discussion about ______”, then you should not be asking here` iKishore wants to participate in a discussion about the relative merits of using conditional preprocessor. – xaxxon Jun 09 '13 at 07:08
  • 1
    In this (and many) cases, if you turn on optimization in your compiler, they'll give the same resulting binary. Your first example has a syntax problem though, since an `#if` cannot work with regular variables. – Joachim Isaksson Jun 09 '13 at 07:09
  • 1
    @xaxxon I don't see that. The question asks which one should be used when, but that's a perfectly legitimate, answerable question rather than a discussion starter. –  Jun 09 '13 at 07:10
  • @delnan when CAN you use it, perhaps. But just "when to use it" implies judgement and context. When that is not specifically provided in the context of the question, it is a discussion starter because it requires long-winded explanations of different contexts and relative merits. – xaxxon Jun 09 '13 at 07:13
  • 2
    Your code isn't C. The C++ community probably has different feelings about this issue. – Jens Gustedt Jun 09 '13 at 07:15
  • @xaxxon Plenty of questions ask "when to use it (vs. this other thing)" and receive objective answers. Two examples: http://stackoverflow.com/q/2189452/395760 and http://stackoverflow.com/q/322715/395760 –  Jun 09 '13 at 07:16
  • Margin vs padding is objective because there is no ability to use one or the other to achieve the same results. I'd suggest the java one goes against the FAQ – xaxxon Jun 09 '13 at 07:43
  • If you rephrase the examples to use `int i = 1;` and run them you will see that the outcomes are quite different. In the `#if` case `i` is unlikely known by the preprocessor and thus gets a default value of 0 when evaluating `#if i == 0`. – Bo R Nov 10 '18 at 13:56

5 Answers5

5

Conditional preprocessor doesn't work like in your first example.

It's working with constants, you see? At compile time, it looks at the various conditions and puts in/omits source code according to it.

For example:

#define HAS_COMPARISON

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

With the define set, it will set the variable i and perform the comparison...in short, it will output This. If you comment that define, the entire block will not be in your program which means that it will always output That, without ever setting the variable or doing the comparison.

That's the most common use of preprocessor defines. You can also define values and compare those to have variable behaviour with the same define, but that's another issue.

Once more: Conditional preprocessor is evaluated at compile time, variable conditions are evaluated at runtime.

Refugnic Eternium
  • 4,089
  • 1
  • 15
  • 24
  • ~ correct me if I'm wrong, is it like if **HAS_COMPARISON** is set to 0 before-compilation then the compiler eliminates block inside _#else_ & _#endif_ like it does for _dead code elimination_. – kishoredbn Jun 09 '13 at 07:12
  • @iKishore The *preprocessor* drops the code before the compiler sees it, which matters because the code that's made conditional may not compile/cause an error when the compiler sees it (e.g. due to type errors or missing functions). –  Jun 09 '13 at 07:14
  • 1
    @iKishore No, you're correct. If it's set to ANY value at all, `#else` is eliminated, while if the `#define` is removed from the code, everything from `#ifdef` to `#else` is eliminated. – Refugnic Eternium Jun 09 '13 at 07:15
5

The example you showed doesn't seem helpful due to lack of other information. But here's an example that #if is useful.

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

The key is that #if is evaluated in compile time, but if is evaluated when program runs.

#if BYTE_ORDER == LITTLE_ENDIAN
//do something
#else
//do something else
#endif
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
3

The use of the preprocessor directives in this case is not entirely useful. But the use of these preprocessor directives is useful in many other cases.

These preprocessor directives can be used for conditional compilation. e.g. If some program has to be developed for multiple platforms then platform-specific constants can be given values. Changing these values compilation specific to the platform can be done while the whole code can be maintained as one big entity.

These are also useful while debugging. Test units can be compiled into the code and ran by using these conditional compilations while debugging and they can be stopped from compiling using these.

Aseem Bansal
  • 6,722
  • 13
  • 46
  • 84
1

Conditional compilation means ifdef-ed out code is never actually in the final linked application. Just using language conditionals means both branches are in the final code making it bigger and potentially harder to test etc.

Use #ifdef etc when you know at compile time what is required. Language conditionals are used when you don't know what you need until runtime.

John3136
  • 28,809
  • 4
  • 51
  • 69
1

benefits of preprocessor is that the code gets thrown out. It doesn't get compiled (which takes time) and it doesn't generate machine code which will be loaded into ram. If the decision is in a VERY tight loop run LOTS of times, there could be a speed improvement. Don't assume this is important unless you actually time it, though.

The detriments of preprocessor is that you obviously have to know the answer at compile time. The source code now contains a lot of code that may not ever be executed. It becomes harder to trace for a human because it's often difficult to determine what those compile-time values would have been.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • Actually, if the condition is a compile-time constant (and simple enough that the preprocessor is an option) the compiler is usually able to infer that and remove the dead code if it's tested with `if`. –  Jun 09 '13 at 07:08
  • True enough. It's always good to keep in mind how smart compilers are. People often write confusing code to try to do some premature optimization and then realize they've not made it faster and it's harder to read/maintain as well. – xaxxon Jun 09 '13 at 07:10