I have this bit of code (part of an interpreter for a garbage-collected Forth system, actually):
#define PRIMITIVE(name) \
do \
{ \
VocabEntry* entry = (VocabEntry*)gc_alloc(sizeof(VocabEntry)); \
entry->code = name; \
entry->name = cstr_to_pstr(#name); \
entry->prev = latest_vocab_entry; \
latest_vocab_entry = entry; \
} \
while (false)
PRIMITIVE(dup);
PRIMITIVE(drop);
PRIMITIVE(swap);
// and a lot more
but there's a problem: in the line
entry->name = cstr_to_pstr(#name);
the name
field is substituted for dup
, drop
, swap
, and the rest. I want the field name to not be substituted.
So, is there any way to solve this, other than simply renaming the macro argument?
For an answer, please explain if there is, in general, a way to suppress the substitution of a macro argument name in the macro body. Don't answer "just do it this way" (please).
No, there is not.
To see why, you need to consider the way macro expansion actually happens. Expanding a function-like macro requires three main steps:
#
or##
operators on them (not relevant in the example since they're single tokens)This is outlined in standard section 6.10.3 (C11 and C99).
The upshot of this is that it is impossible to write some kind of macro that can take
name
and abuse the suppression-rules of '##' or anything like that, because the replacement step in the body ofPRIMITIVE
must run completely before any of the macros within the body are allowed their turn to be recognised. There is nothing you can do to mark a token within the replacement list for suppression, because any marks you could place upon it will only be examined after the replacement step has already run. Since the order is specified in the standard, any exploit you find that would let you mark a token in this way is a compiler bug.Best I can suggest if you're really set on not renaming the macro argument is to pass
na
andme
as separate arguments to a concatenation macro; the tokenname
will only be formed after replacement is done and the list is no longer being examined for parameter names.EDIT wish I typed faster.
You can define a different macro to expand to
name
, like this:and change the
name
field in thePRIMITIVE
macro to use the new macro, like this:Other than using something different from the parameter name in the macro body or changing the parameter name, there is no other way to do this in the C language. Per C 2011 (N1570) 6.10.3.1 1, when a function-like macro is recognized, parameter names are immediately substituted except when
#
or##
is present, and there no other exceptions:The
#
token changes the parameter name to a string, which is no use in this situation. The##
token expands the parameter name and pastes it together with an adjacent token, which is also no use in this situation.No, there is no way to suppress the replacement within a macro's body of a token identical to that of a declared argument to said macro. Every possible solution short of jumping into the preprocessor code will require you to rename something, either the argument name or the name of the field (potentially just for purposes of that macro, as Eric's answer does).