hugomg
hugomg

Reputation: 69964

Is it possible to put a preprocessor conditional inside a C macro?

Is there a way to write a C preprocessor macro that expands to different things depending on what argument it receives?

#define foo() ???

/* 1 */
foo(name)

/* 2 */
foo(_)

Desired result:

/* 1 */
int name;

/* 2 */
/*ignore*/

Yes, I know macros are evil. I'm asking this mostly out of curiosity.

Upvotes: 15

Views: 9590

Answers (3)

yyny
yyny

Reputation: 1736

With the tricks described here, it is possible to do what you want at compile time.

You could use the EQUAL macro defined at the end of the document, and do this:

#define COMPARE__(x) x
#define OPTION_0(x) int x;
#define OPTION_1(x) /* nothing */
#define foo(x) CAT(OPTION_, EQUAL(_, x))(x)

foo(name1) // int name1;
foo(_)     // /* nothing */
foo(name2) // int name2;

Upvotes: 3

Alex Celeste
Alex Celeste

Reputation: 13390

To expand on Gavin Smith's answer, you actually can check conditions within a macro expansion:

#define FOO_name 1
#define FOO__ 0

#define CONC(a,b) a##_##b

#define IF(c, t, e) CONC(IF, c)(t, e)
#define IF_0(t, e) e
#define IF_1(t, e) t

#define FOO(x) IF(CONC(FOO,x), int x;, )

FOO(name) // -> int name;
FOO(_)    // -> /*nothing*/

If you're feeling adventurous you can easily extend IF to allow commas, suppress macro expansion, etc. with helper macros.

As above though this does require that you know all of the desired names in advance.

Upvotes: 17

Gavin Smith
Gavin Smith

Reputation: 3154

Perhaps try some multi-stage macro expansion? This is the strategy used by the Boost preprocessor/control/if library.

#define FOO_NAME 1
#define FOO__ 2

#define CONC(a,b) a##_##b
#define FOO(x) CONC(FOO,x)

I don't think there is any way to check conditions within a C macro expansion.

The best thing I could come up with is to covert the macro arguments to a string literal using the # stringizing operator, and then checking using run-time functions. (This won't work for your case, though, where you want to output variable declarations.)

For example, the following prints "011":

#define FOO(x) (strcmp("NAME", #x) ? 1 : 0)

main()
{
    printf("%d", FOO(NAME));
    printf("%d", FOO(1));
    printf("%d", FOO(2));
}

The compiler would likely optimize the strcmp comparisons at compile-time so it would be no more inefficient than it would have been had genuine pre-processor conditionals been available. However, making FOO a normal function would be clearer and probably just as efficient.

Upvotes: 9

Related Questions