C++: Can a MACro Expand "Abc" into 'A', 'B', 'C'

Macro that expands its only argument into its component characters

No. This functionality is not provided by the C preprocessor.

Depending on your use case, a string might be equivalent (except for the null byte), so stringifying might work as well.

You might have a look at m4, a more advanced preprocessor by K&R. Maybe it provides the functionality you need.

Macro expanding to same operator

Common Lisp provides compiler macros.

These can be used for such optimizations. A compiler macro can conditionally decline to provide an expansion by just returning the form itself.

Using preprocessor macros to compose another macro call


Why can't I compose a macro call from two or more macro expansions, doesn't preprocessor expand them recursively?

You can compose macros. The pre-processor does expand macros recursively.

However, it doesn't expand the macros width first. It expands them depth first.

You are running into a problem because you want the pre-processor to expand the macros width first.

You can read more about recursive macro expansion in 16.3.4 Rescanning and further replacement of the C++11 standard.

Nested ## operator in C Preprocessor

The GCC docs explain it this way:

Macro arguments are completely macro-expanded before they are
substituted into a macro body, unless they are stringified or pasted
with other tokens
.

(emphasis added)

The operands of the ## (token pasting) operator, on the other hand, are not macro-expanded before being pasted together. So, given

CONCATENATE(a,CONCATENATE(b,c))

the preprocessor does not expand CONCATENATE(b,c) before expanding the outer macro's body because it is an operand of ##. The preprocessor instead performs token pasting before rescanning for more macros to expand, so

a ## CONCATENATE(b,c)

becomes

aCONCATENATE(b,c)

before the rescan, and there is no macro aCONCATENATE (but if there were, then it would be expanded).

On the other hand, with

CONCATENATE2(a,CONCATENATE2(b,c)),

the argument CONCATENATE2(b,c) is not an operand of the ## (or #) operator, so it is expanded before being substituted into the macro body, ultimately yielding

CONCATENATE(a, bc)

as the first expansion of the outer macro. That is rescanned for further expansions, yielding

abc

Complicated multi-argument #define macro for strings

The only solution I can think of is to run your code through a suitable script (probably just some light awk), that does the substitution before your code reaches the pre-compiler.

Depending on your environment you could do this as a "Pre-Build Event" in Visual Studio, or just add a step directly into your makefile.

Preprocessing operator ##

If you have

#define CONCAT(x,y)   x##y
#define CONCAT2(x,y) CONCAT(x,y)

then when the preprocessor sees

CONCAT(a,CONCAT(b,c))

it knows that the replacement list for CONCAT(x,y) is x##y, so it going to replace x with a and y with CONCAT(b,c). The only question is, will it expand a and/or CONCAT(b,c) before the replacement? a is not a macro so no expansion is possible, and in the replacement list x##y, the y is preceded by ## so no expansion is done on the argument CONCAT(b,c). So the replacement is done without expansion, and the replacement list becomes a##CONCAT(b,c), and then before it checks for more macros, it processes the ## and the replacement list becomes aCONCAT(b,c).

If the preprocessor sees

CONCAT2(a,CONCAT2(b,c))

it knows that the replacement list for CONCAT2(x,y) is CONCAT(x,y), so it going to replace x with a and y with CONCAT2(b,c). The only question is, will it expand a and/or CONCAT2(b,c) before the replacement? a is not a macro so no expansion is possible, and in the replacement list CONCAT(x,y), the y is NOT preceded by # or ##, or followed by a ##, so CONCAT2(b,c) is COMPLETELY expanded BEFORE replacement. So CONCAT2(b,c) is expanded to CONCAT(b,c), which is expanded to b##c, no further expansion is possible, so the y is replaced by b##c. The replacement list x##y becomes a##b##c, and either it becomes ab##c and then abc, or it becomes a##bc and then abc.

If the preprocessor sees

CONCAT2(a,CONCAT(b,c))

it knows that the replacement list for CONCAT2(x,y) is CONCAT(x,y), so it going to replace x with a and y with CONCAT(b,c). The only question is, will it expand a and/or CONCAT(b,c) before the replacement? a is not a macro so no expansion is possible, and in the replacement list CONCAT(x,y), the y is NOT preceded by # or ##, or followed by a ##, so CONCAT(b,c) is COMPLETELY expanded BEFORE replacement. So CONCAT(b,c) is expanded to b##c, no further expansion is possible, so the y is replaced by b##c, the replacement list x##y becomes a##b##c, and either it becomes ab##c and then abc, or it becomes a##bc and then abc.

If the preprocessor sees

CONCAT(a,CONCAT2(b,c))

it knows that the replacement list for CONCAT(x,y) is x##y, so it going to replace x with a and y with CONCAT2(b,c). The only question is, will it expand a and/or CONCAT2(b,c) before the replacement? a is not a macro so no expansion is possible, and in the replacement list x##y, the y is preceded by ## so no expansion is done on the argument CONCAT2(b,c). So the replacement is done without expansion, and the replacement list becomes a##CONCAT2(b,c), and then before it checks for more macros it processes the ## and the replacement list becomes aCONCAT2(b,c).

You might be thinking that

#define CONCAT2(x,y)  CONCAT(x,y)

means that

CONCAT2(x,y) should be the same as CONCAT(x, y)

but remember that:

  1. The replacement list for CONCAT(x,y) is x##y, and because x is followed by ## and y is preceded by ##, when the preprocessor sees an instance of the CONCAT macro, it will not expand the arguments that correspond to x or y before substitution. However the replacement list for CONCAT2(x,y) is CONCAT(x,y) and neither x nor y in the replacement is preceded by # or ## or followed by ##, so when the preprocessor sees an instance of the CONCAT2 macro, it will expand the any macros in the argmuments COMPLETELY BEFORE replacement.

  2. Macro expansion of arguments (if allowed) takes place BEFORE substitution. So in CONCAT2(a,CONCAT(b,c)) the CONCAT(b,c) argument is expanded BEFORE the replacement. So we get CONCAT2(a, b##c) and not CONCAT(a, CONCAT(b,c)).

Parameterized macros involving the ## operator in the replacement-list

When the preprocessor detects a function-like macro invocation while scanning a source line, it completely expands the macro's arguments before substituting them into the macro's replacement text, except that where an argument appears as an operand of the stringification (#) or token-pasting (##) operator, its literal value is used for the operation. The resulting replacement text, with expanded arguments and the results of any # and ## operations substituted, is then rescanned for additional macros to expand.

Thus, with ...

CONCAT(a, CONCAT(b,c))

... the literal values of both arguments are used as operands for the token-pasting operation. The result is ...

aCONCAT(b,c)

. That is rescanned for further macros to expand, but aCONCAT is not defined as a macro name, so no further macro expansion occurs.

Now consider ...

CONCAT2(a, CONCAT2(b,c))

. In CONCAT2, neither argument is an operand of # or ##, so both are fully macro-expanded before being substituted. Of course a is unchanged, but CONCAT2(b,c) expands to CONCAT(b,c), which upon rescan is expanded to bc. By substitution of the expanded argument values into its replacement text, the outer CONCAT2 invocation expands to ...

CONCAT(a, bc)

. That expansion is then rescanned, in the context of the surrounding source text, for further macro expansion, yielding ...

abc

. That is again rescanned, but there are no further macro expansions to perform, so that's the final result.



Related Topics



Leave a reply



Submit