views:

212

answers:

4

I'm trying to use preprocessor tricks to declare a magic variable. Something like this:

DECLARE(x)

should expand to

int _DECLARED_VARIABLE_x_LINE_12

if the declaration was on line 12 of the input source. I was trying to use the ## token-pasting command and the __LINE__ macro, but I either get an uninterpreted "__LINE__" in there or the preprocessor seems to completely ignore my line. My current guess is:

 #define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
+6  A: 

The normal trick in such cases is to use a second macro. However, that does not seem to work with GCC (4.5.1 on MacOS X 10.6.4), and a third level of macro was needed:

#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__

#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)

int DECLARE(y);
int DECLARE40(c) = 129;

Output of 'gcc -E':

# 1 "magicvars.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "magicvars.c"






int _DECLARED_VARIABLE_y_LINE___LINE__;
int _DECLARED_VARIABLE_c_LINE_8 = 129;

I'm not sure I have a good explanation of why the third level of macro was needed.

I am also curious to know how you are ever going to refer to these variables after you've created them.


I went through a number of variations before managing to hit on the one that worked:

#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__

#define DECLARE11(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE10(x) DECLARE11(x, __LINE__)

#define DECLARE23(line) _LINE_ ## line
#define DECLARE22(x) _DECLARED_VARIABLE_ ## x
#define DECLARE21(x, line) DECLARE22(x) ## DECLARE23(line)
#define DECLARE20(x) DECLARE21(x, __LINE__)

#define DECLARE32(line) _LINE_ ## line
#define DECLARE31(x, line) _DECLARED_VARIABLE_ ## x ## DECLARE32(line)
#define DECLARE30(x) DECLARE31(x, __LINE__)

#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)


int DECLARE(y);
int DECLARE10(z) = 12;
int DECLARE20(a) = 37;
int DECLARE30(b) = 91;
int DECLARE40(c) = 129;

Have fun working out why the non-working ones didn't work. They did, however, point me towards the working answer. (I note that the Sun C compiler produces essentially the same results as GCC on the same input.)

Jonathan Leffler
+1 for perseverance.
RBerteig
Awesome answer, thank you very much!
redtuna
to answer your other question, I'm not going to refer to those variables in the code; I need this for some compiler tools I'm tinkering with.
redtuna
+1  A: 

There was an issue with __LINE__ in debug mode with Visual Studio if you were using Edit and Continue. Here is a reference to it. That issue is a few years old though. If that issue is resolved, then Jonathan Leffler's solution will work fine.

D.Shawley
+4  A: 

The preprocessor removes the ## operators from the macro replacement list before attempting to look for further macros for recursive replacement. This means that your reference to __LINE__ gets "glued" to the rest of the macro before it has a chance to get recognized as __LINE__ and replaced with the actual line number.

For this reason, if you want to embed the line number into your macro, you have no other choice but to pass it through a macro parameter

#define DECLARE_(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE(x) DECLARE_(x, __LINE__)

And that will formally solve the immediate problem in your original macro definition.

However, this still will not work as expected due to another quirk in C/C++ preprocessor specification: parameter names adjacent to ## are replaced with the corresponding arguments values without the recursive macro expansion in the argument value. I.e. L will be replaced with __LINE__, without changing __LINE__ to the actual line number first.

To ensure the recursive macro expansion for parameter L, one needs to introduce another "level of indirection" in macro definition

#define DECLARE__(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE_(x, L) DECLARE__(x, L)
#define DECLARE(x) DECLARE_(x, __LINE__)

In this case, when processing DECLARE_(x, L) macro, the preprocessor will handle L recursively: first replace it with __LINE__ and then replace __LINE__ with the actual line number. DECLARE__ will receive the complete line number.

AndreyT
+1 for good explanation
0x69
A: 

There are two special expansion rules regarding ## operator:

  1. Operands to ## operator are not expanded before pasting.
  2. Macro arguments are not expanded if they are concatenated with ##.
0x69