Defining define

January 30, 2017

When I encounter a preprocessor branch in code I usually find myself struggling to recall the difference between #if, #ifdef, and #if defined. This post is an attempt to provide myself with a quick reference. Hopefully it might help others as well.

This chart summarizes things:

Checks for existence Numeric defines Supports && and || Supports !
#if No Yes Yes No
#ifdef Yes No No One condition (#ifndef)
#if defined Yes No Yes Many conditions (!defined())

The details are below.

Start with #if

Let’s start with this code:

#define DEFINED_VALUE

#if DEFINED_VALUE
#warning "#if DEFINED_VALUE" is active
#else
#warning "#if DEFINED_VALUE" is not active
#endif

It produces a compiler error:

test.cpp:3:18: error: expected value in expression
#if DEFINED_VALUE

So to use #if, we need to have an actual value, like this.

#define DEFINED_VALUE 0
test.cpp:6:2: warning: "#if DEFINED_VALUE" is not active

Then a non-zero value will “activate” the branch.

#define DEFINED_VALUE 1
test.cpp:6:2: warning: "#if DEFINED_VALUE" is active

It is also possible to use #if for logical conditions like && and ||.

#define ZERO 0
#define ONE 1

#if ONE && ONE
#warning 1 and 1 is active
#endif

#if ONE || ZERO
#warning 1 or 0 is active
#endif
test.cpp:5:2: warning: 1 and 1 is active
test.cpp:9:2: warning: 1 or 0 is active

Next up: #ifdef

Now let’s try #ifdef.

#define DEFINED_VALUE

#ifdef DEFINED_VALUE
#warning "#ifdef DEFINED_VALUE" is active
#else
#warning "#ifdef DEFINED_VALUE" is not active
#endif
test.cpp:4:2: warning: "#ifdef DEFINED_VALUE" is active

So just the presence of the defined value will activate this branch. We can comment it out to deactivate it.

//#define DEFINED_VALUE
test.cpp:6:2: warning: "#ifdef DEFINED_VALUE" is not active

We can use #ifndef to determine if a value is not defined.

#define DEFINED_VALUE

#ifndef DEFINED_VALUE
#warning "#ifndef DEFINED_VALUE" is active
#else
#warning "#ifndef DEFINED_VALUE" is not active
#endif
test.cpp:6:2: warning: "#ifndef DEFINED_VALUE" is not active

Can we do Boolean operations, as with #if?

#define ZERO 0
#define ONE 1

#ifdef ONE && ZERO
#warning 1 and 0 is active
#else
#warning 1 and 0 is not active
#endif
test.cpp:4:12: warning: extra tokens at end of #ifdef directive
#ifdef ONE && ZERO
test.cpp:5:2: warning: 1 and 0 is active

No, it seems Boolean conditions are not possible here. Even worse, we only get a warning, and the condition is evaluated as if the #ifdef is true! In this case, the actual behavior is the opposite of my intuition. This could be lost in a sea of warnings, and end up being difficult to track down.

In addition, numeric values are only checked for existence.

#define ZERO 0

#ifdef ZERO
#warning "#ifdef ZERO" is active
#else
#warning "#ifdef ZERO" is not active
#endif
test.cpp:4:2: warning: "#ifdef ZERO" is active

So maybe surprisingly, the behavior of #ifdef ZERO and #if ZERO are opposite.

Last but not least: #if defined

Finally, we can use the defined keyword, which something like a function call.

#define DEFINED_VALUE

#if defined(DEFINED_VALUE)
#warning "#if defined(DEFINED_VALUE)" is active
#else
#warning "#if defined(DEFINED_VALUE)" is not active
#endif
test.cpp:4:2: warning: "#if defined(DEFINED_VALUE)" is active

If the value is not defined, we get the other leg of the branch:

//#define DEFINED_VALUE
test.cpp:6:2: warning: "#if defined(DEFINED_VALUE)" is not active

We can also check for a value that is not defined.

//#define DEFINED_VALUE

#if !defined(DEFINED_VALUE)
#warning "#if !defined(DEFINED_VALUE)" is active
#else
#warning "#if !defined(DEFINED_VALUE)" is not active
#endif
test.cpp:4:2: warning: "#if !defined(DEFINED_VALUE)" is active

If addition, this syntax supports Boolean operators (&&, ||, and !):

#define DEFINED

#if defined(DEFINED) && !defined(UNDEFINED)
#warning "#if defined(DEFINED) && !defined(UNDEFINED)" is active
#else
#warning "#if defined(DEFINED) && !defined(UNDEFINED)" is active
#endif
test.cpp:4:2: warning: "#if defined(DEFINED) && !defined(UNDEFINED)" is active

What about numeric values though?

#define ZERO 0

#if defined(ZERO)
#warning "#if defined(ZERO)" is active
#else
#warning "#if defined(ZERO)" is not active
#endif
test.cpp:4:2: warning: "#if defined(ZERO)" is active

The behavior of #if defined is the same as the behavior of #ifdef in this respect.


Content © Josh Peterson

Site design by Sirupsen