Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way of passing macro names as arguments to nested macros without them being expanded when the outermost macro is expanded?

Tags:

c++

c

macros

(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.

like image 482
R160K Avatar asked Feb 13 '15 06:02

R160K


People also ask

What is the correct format for naming a macro with multiple arguments?

To create a macro with arguments, put them in parentheses separated by commas after the macro name, e.g. then BadSquare(3+4) would give 3+4*3+4, which evaluates to 19, which is probably not what we intended.

How do you pass a macro as a parameter?

To assign a macro that you pass arguments to a button, shape, image, or any object, you first right-click that object and click Assign Macro and then type the name of the macro and the argument, following the pattern described in the above examples, and then click OK. 'show_msg "I clicked a button!"'

Are nested macros allowed?

No macro can be called until it has been edited. There is no limit to the number of nestings allowed for inner macro definitions. The lack of parameterization can be overcome in some cases by using the AINSERT statement. This lets you generate a macro definition from within another macro generation.

Can a macro call another macro in C?

Here is an example of how to run another macro from a macro using the Call Statement. Just type the word Call then space, then type the name of the macro to be called (run). The example below shows how to call Macro2 from Macro1. It's important to note that the two macros DO NOT run at the same time.


1 Answers

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..

like image 175
Nim Avatar answered Oct 05 '22 22:10

Nim