voyta
voyta

Reputation: 60

How to parametrize single string containing # in C preprocessor?

I want to create parameterized preprocessor macro for IBM Metal C Prolog.

The initial unparametrized form is #pragma prolog(Foo, " #MCPROLG MAIN=(YES,16,132)") The real prolog is more complex, but for the sake of the question the important part is that there are values within a string.

#pragma directive itself can't be part of a macro, so I replace that with _Pragmalike that: _Pragma("prolog(Foo, \" #MCPROLG MAIN=(YES,16,132)\")")

I can parameterize Foo like this:

#define STR(...) #__VA_ARGS__
#define PROLOG(function) _Pragma(STR(prolog( function , " #MCPROLG MAIN=(YES,16,132)")))

How can I create macro that parameterizes the value 16?

It appears that I need to concatenate strings within preprocessor, I've tried following approaches. All use this stringization macro:

#define STR(...) #__VA_ARGS__
  1. Token that is replaced with 16 (let's name it size) can't be within a string itself so that it is replaced.

    #define PROLOG(function, size) _Pragma(STR(prolog( function , " #MCPROLG MAIN=(YES, size ,132)")))

  2. _Pragma only accepts a single string, so I can't peruse C string concatenation like this:

    #define PROLOG(function, size) _Pragma(STR(prolog( function , " #MCPROLG MAIN=(YES," #size ",132)")))

  3. I can't stringize the whole second argument of prolog like this:

    #define PROLOG(function, size) _Pragma(STR(prolog( function , STR( #MCPROLG MAIN=(YES, size ,132)))))

because #MCPROLG needs to stay within a string so that its # is not treated as stringization token.

Upvotes: 0

Views: 200

Answers (1)

H Walters
H Walters

Reputation: 2674

To address issue 1 (need to expand a parameter in the replacement list), you need an indirect stringify macro:

#define STR(X) STR_I(X)
#define STR_I(X) #X

You may make this variadic if you want but it's not necessary here (the commas in your string are surrounded by parentheses; the preprocessor will match those; e.g., FOO(A=(B,C,D)), given FOO is a function-like macro, has one argument).

To address issue 2, yes, you need to stringify the whole thing. Effectively there's no such thing as string literal concatenation to the preprocessor (because it runs in translation phase 4, and string literal concatenation doesn't happen until translation phase 6).

To address issue 3, just produce a hash from another macro (root it at an object-like macro, where # has no special meaning):

#define HASH #
#define HASHM() HASH

The function-like variant allows you to produce the same hash right next to something else (HASHMCPROLG does nothing useful; HASH MCPROLG produces # MCPROLG, HASHM()MCPROLG produces #MCPROLG).

Those pieces in hand, the rest is easy:

#define PROLOG(FN_,SZ_) _Pragma(STR(prolog(FN_, STR( HASHM()MCPROLG MAIN=(YES,SZ_,132)))))

Here I'm assuming you also need an end parentheses around the pragma prolog and that in the question this was a typo; that is, it should be:

_Pragma("prolog(foo, \"#MCPROLG MAIN=(YES,16,132)\")")

...not:

_Pragma("prolog(foo, \"#MCPROLG MAIN=(YES,16,132)\"")

Upvotes: 1

Related Questions