10

(Apologies for the long title, but I couldn't think of a less specific one which would be clear enough)

I need to pass the name of an (object-like) macro to a nested (function-like) macro, as in the following (trivial) example:

#define ROOT_FUNC(INPUT) int v_ ## INPUT = INPUT
#define CALLER_FUNC(INPUT) ROOT_FUNC(INPUT)

#define INTA 1
#define INTB 2
#define INTC 3

Now, if I write ROOT_FUNC(INTA); in my code I get an integer variable called v_INTA with the value 1. If I define a variable in code, int INTD = 4;, and then write CALLER_FUNC(INTD); I end up with an integer variable called v_INTD with the value 4.

But if I write CALLER_FUNC(INTA); I get an integer variable called v_1 with a value of 1, because INTA is expanded to 1 at the time CALLER_FUNC is expanded, before ROOT_FUNC is expanded (i.e. ROOT_FUNC(1) is what gets expanded).

If I change line 2 to: #define CALLER_FUNC(INPUT) ROOT_FUNC(#INPUT) (i.e. stringifying INPUT), a compiler error occurs because it is being asked to define an integer variable called v_"1" (an invalid name) and give it the value "1" (a non-integer value).

I know the preprocessor is fairly primitive, but is there any way of achieving what I'm after?

(Second edit for further clarification, I want CALLER_FUNC(INTA); to expand first to ROOT_FUNC(INTA);, then to int v_INTA = 1; – i.e. I want INTA to be expanded inside ROOT_FUNC, rather than outside it. I am looking for an answer in principle, not just any way to change CALLER_FUNC to produce the result int v_INTA = 1;, which would be trivial).


P.S. In case you are wondering, I originally had a use case involving signal handling (e.g. taking macro names like SIGINT as inputs for nested macros), but got around these limitations by simplifying my structure and abandoning nested macros; hence this question is purely academic.

R160K
  • 283
  • 2
  • 10
  • 1
    I'm still not clear on what you want. Please show an example of what the expected output is. –  Feb 13 '15 at 06:15
  • What's `MASTER`? Did you mean `ROOT_FUNC`? – T.C. Feb 13 '15 at 06:16
  • 1
    @remyabel The desired output would be: `CALLER_FUNC(INTA);` expanding to `ROOT_FUNC(INTA);`, then to `int v_INTA = 1;` (the spefic example is just a random and trivial one). At the moment it expands to `ROOT_FUNC(1);` and then to `int v_1 = 1;` (i.e. INTA is expanded before it is passed to ROOT_FUNC(), whereas I would like it to happen after). – R160K Feb 13 '15 at 06:23
  • @T.C. I did indeed – have changed. – R160K Feb 13 '15 at 06:24
  • I don't think this is possible. If I'm reading the spec correctly, arguments are macro-expanded before they are substituted into the replacement list, except when they are the operand of a `#` or `##`, but in those cases you'd have no way to get the argument back. – T.C. Feb 13 '15 at 06:48
  • @remyabel That would give the desired output in this specific example (as would just `#define CALLER_FUNC(INPUT) int v_ ## INPUT = INPUT`), but it is not really addressing what the question is asking: `CALLER_FUNC(INTA);` gets expanded to `int v_INTA = EXPAND(1);` and then to `int v_INTA = 1;` rather than going through `EXPAND(INTA);` – INTA is still expanded with the outermost macro. – R160K Feb 13 '15 at 07:00
  • What are you seeking if the `#define CALLER_FUNC(x) int v_ ## x = x` does not do what you are after? It gives the desired output as requested in the question/comments. You can define `#define VAR_NAME(x) v_ ## x` so that you can subsequently do things like `int z = VAR_NAME(INTA) + VAR_NAME(INTB);` and get the right variables mentioned. – Jonathan Leffler Feb 13 '15 at 07:18
  • @JonathanLeffler the question was more about what is mechanically possible with the precompiler rather than how to produce a specific result in a trivial example. Macros are just shorthand so by definition any specific example offered to illustrate the problem could be solved by simply going through the code and manually expanding them (as you have done here) – the question is about whether it is possible to choose the layer at which a macro gets expanded when it is passed as an argument to a nested function macro ... and the answer is probably no. – R160K Feb 13 '15 at 07:31
  • Correct: the answer is No. The C preprocessor is fairly primitive in many ways, and you don't have control over when macros are expanded. – Jonathan Leffler Feb 13 '15 at 07:59
  • possible duplicate of [Macro expansion and stringification: How to get the macro name (not its value) stringified using another macro?](http://stackoverflow.com/questions/11693219/macro-expansion-and-stringification-how-to-get-the-macro-name-not-its-value-s) – Jonathan Mee Feb 13 '15 at 19:33

1 Answers1

6

If you can expand the first macro to take two arguments, you could get it to work like this:

#define FUNC(intname, intv) int v##intname = intv
#define CALL_FUNC(intv) FUNC(_##intv, intv)

#define INT1 1
#define INT2 2

int main(void)
{
  int INTD = 4;

  CALL_FUNC(INT1);
  CALL_FUNC(INT2);
  CALL_FUNC(INTD);
}

The output (from GCC), looks something like this:

int main(void)
{
  int INTD = 4;

  int v_INT1 = 1;
  int v_INT2 = 2;
  int v_INTD = INTD; // not sure if you want the value of INTD here - I guess it doesn't matter?
}

Which I guess is what you are after - if I read your question right?

The token pasting prevents the preprocessor from expanding it out and simply generates a new token which is passed to the second macro (which then simply pastes that together to form the variable), the value (which is expanded) is passed down as the second argument..


EDIT1: Reading more through what you are after, I'm guessing the above trick is not what you reall want...ah well..

Nim
  • 33,299
  • 2
  • 62
  • 101
  • 2
    This is actually a very good hack – indeed, this would have worked in my original (now abandoned) use case. This of course applies only to the subset of cases where an inner function wants to paste the macro, but there are only three possible cases: the inner function can paste, expand or stringify the macro, and with the latter two it is irrelevant where in the chain the macro is expanded/stringified, the result is always the same. Hence, I think we now have a complete model. The only downside is that multiple caller functions might have to contain the same paste, lessening macro efficiency. – R160K Feb 13 '15 at 10:04