People recommend #ifdef
for conditional compilation by a wide margin. A search for #ifdef
substantiates that its use is pervasive.
Yet #ifdef NAME
(or equivalently #if defined(NAME)
and related #ifndef NAME
(and #if !defined(NAME)
) have a severe flaw:
header.h
#ifndef IS_SPECIAL
#error You're not special enough
#endif
source.cpp
#include "header.h"
gcc -DIS_SPECIAL source.cpp
will pass, obviously, as will
source1.cpp
#define IS_SPECIAL 1
#include "header.h"
But, so will
source0.cpp
#define IS_SPECIAL 0
#include "header.h"
which is quite the wrong thing to do. And some C++ compilers, passed a file processed in C mode (due to extension or command-line option) effectively do #define __cplusplus 0
. I have seen things break when
#ifdef __cplusplus
extern "C" {
#endif
/* ... */
#ifdef __cplusplus
}
#endif
was processed in C mode, where extern "C"
is invalid syntax, because __cplusplus
was in fact automatically defined to 0
.
On the other hand, this behaves correctly for all compilers:
#if __cplusplus
extern "C" {
#endif
/* ... */
#if __cplusplus
}
#endif
Why do people still use #ifdef
in this scenario? Are they simply unaware that #if
works perfectly fine on undefined names? Or is there an actual disadvantage to #if
vs #ifdef
for conditional compilation?
Obviously, #ifdef
does have valid uses, such as providing default values for configurable parameters:
#ifndef MAX_FILES
#define MAX_FILES 64
#endif
I'm only discussing the case of flag testing.
__cplusplus == 0
for why this is the wrong test. Or do you think that changing a setting from1
to0
shouldn't turn it off? – Pilpul#ifdef
, and then it's not even clear what the "better" alternative is until nearly the end. For a while I thought that you wanted people to use#ifndef
. – Clarsach#define HAVE_READLINE 0
to do the same thing as#define HAVE_READLINE 1
. – Pilpul#ifdef
for flag testing only because of personal preference. I'm asking whether there is any case in which it is objectively better. – Pilpul__cplusplus
, nor shall it define it in any standard header." A compiler in C mode defining it anyways is broken, so this particular example isn't a very strong argument for#if
over#ifndef
. – Annamariaannamarie#ifdef
rests in that there is only one level of logic involved: defined/undefined. On the other hand,#if
admits two layers of logic: defined/undefined and zero/nonzero, when only one was required for conditional compilation.#if
then conflates two of the three cases (undefined and defined-but-zero) together in your proposed usage, which may surprise some. The principle of least astonishment and Occam's Razor would have you prefer the simplest, best-understood construction that is still good enough, but no simpler. – Annamariaannamarie#define THING
followed by#if THING
yields unexpected results. – Behn__STDC__
as 0. Since they weren't compliant, there was nothing technically wrong, but they were a pain to use. If you have to use retrograde buggy compilers, you have to take special precautions. For most people, most of the time, working with#if defined
or its equivalents is perfectly reasonable. If people insist on breaking the compilation by defining macros incorrectly, people will break the compilation — there's not much you can do to stop idiots from being idiots (though many have tried, few have succeeded; idiots are far too clever). – Auston#define USE_SSL 1
? – Pilpuldefined
, or by being used as a value. If a macro is designed for use as a presence/absence test, then changing the value and expecting different behaviour is silly; that is not what the macro is designed for, and making a change from 1 to 0 or any other value will not make the slightest odds, and the person who changes it expecting a difference doesn't understand the code they're trying to modify/influence. – Auston#if
s exactly for this reason. If the tested macro is undefined, the preprocessor interprets it as falsy so everything works fine. The only place I found there's a difference between if and ifdef is in header double-inclusion guards with gcc. gcc optimizes out file reads if it sees an#ifdef
guard, but it doesn't work (isn't optimized out) with#if
. – Dantedanton