Jasmine
Jasmine

Reputation: 16165

Is it possible to compare #ifdef values for conditional use

I'm trying to come up with a generic, easy to use way to only run certain code, depending upon the api I am using at the time.

In a header:

#define __API_USED cocos2d-x

#define COCOS2DX  cocos2d-x
#define OPENGL opengl

#ifdef __API_USED == COCOS2DX
    #define USING_COCOS2DX
    #undef USING_OPENGL
#endif

in source:

#ifdef USING_COCOS2DX
    ......
#endif

However I don't think this would work.

Is there a way to accomplish what I am looking to do?

Upvotes: 15

Views: 37208

Answers (3)

Nat Goodspeed
Nat Goodspeed

Reputation: 195

This works for me with clang 8.1.0 (from Xcode 8.3.2). Suppose, in a header file, we want to test CONFIG for the value special. In any given translation unit, CONFIG might be unset, or might be set to special, or might be set to something else.

#define CAT_HELPER(lhs, rhs) lhs##rhs
#define CAT(lhs, rhs) CAT_HELPER(lhs, rhs)

#define TEST_PREFIX_special 1

#if CAT(TEST_PREFIX_, CONFIG)
#pragma message("detected CONFIG == 'special'")
#else
#pragma message("CONFIG != 'special'")
#endif

The double indirection (CAT() calls CAT_HELPER()) is important.

This tactic relies on #if expanding an undefined macro as 0.

Upvotes: 0

Keith Thompson
Keith Thompson

Reputation: 263177

If I understand this correctly, cocos2d-x is one of several possible APIs.

The preprocessor can test whether a symbol is defined or not (using #ifdef and the defined operator), and it can evaluate constant integer expressions (using #if).

One approach would be to define a numeric code for each API:

#define COCOS2X         1
#define ANOTHER_API     2
#define YET_ANOTHER_API 3
/* ... */

and then:

#define API_USED COCOS2DX
#if API_USED == COCOS2DX
    #define USING_COCOS2DX
    #undef USING_OPENGL
#elif API_USED == ANOTHER_API
    /* ... */
#elif API_USED == YET_ANOTHER_API
    /* ... */
#endif

Note that I've changed your macro name __API_USED to API_USED. Identifiers starting with two underscores (or with an underscore followed by an uppercase letter) are reserved to the implementation for all purposes; you shouldn't define them in your own code.

One drawback of this approach is that misspellings won't be flagged; the preprocessor quietly replaces any undefined identifiers with the constant 0.

It's probably better to have an identifier for each API, and define it if and only if that API is being used:

#define USING_COCOS2X
/* #undef USING_COCOS2X */

and then:

#if USING_API_COCOS2X
    #undef USING_OPENGL
#endif

Testing whether a macro is defined or not tends to be more robust than testing whether it has a specific value.

You then just have to make sure that the USING_API_* macros (if there are several) are defined consistently.

Upvotes: 7

Ross Ridge
Ross Ridge

Reputation: 39551

You can but you need to do it like this:

#define __API_USED COCOS2DX

#define COCOS2DX  1
#define OPENGL 2

#if __API_USED == COCOS2DX
    #define USING_COCOS2DX
    #undef USING_OPENGL
#endif

As Keith Thompson explained undefined tokens (macros) like cocos2d and x evaluate to 0 so you need to define values for the macros you're using.

Upvotes: 18

Related Questions