C Programming: Preprocessor, macros as tokens
Asked Answered
H

3

2

I'm trying to do something that is conceptually similar to this, but can't seem to get it to work (error shown at end) any ideas?

#include <stdio.h>

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR(prefix) prefix##_def_##SUFFIX
  printf( "%d\n" , VAR(abc) );
  return 0;
}

// untitled:8: error: ‘abc_def_SUFFIX’ undeclared (first use in this function)
Higgler answered 20/11, 2009 at 1:1 Comment(4)
const argv? First time I see such a thing! The idea seems nice, but I'm not sure I like it: it makes main non-conformant and prevents me from doing something I never did ;)Veracity
It's not non-conformant. argv can be declared as something equivalent to char* argv[] (C99 5.1.2.2.1), and adding the const there doesn't change anything except what main() is allowed to do with it (without a cast). Remember that a pointer to a non-const can be converted to a pointer to a const no problem - right down to the fact that values of those pointers will compare equal (6.3.2.3/2).Stowell
Right, thanks Michael. It's the other way around (removing const) that would make it non-conformant. I'm beginning to like it!Veracity
Hi, sorry for that distraction, I should have taken that out. When using TextMate, typing main followed by tab fills out a scaffold for the main method, and that is part of it.Higgler
C
11

You just need additional indirection:

#include <stdio.h>

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR3(prefix, suffix) prefix##_def_##suffix
  #define VAR2(prefix, suffix) VAR3(prefix, suffix)
  #define VAR(prefix) VAR2(prefix, SUFFIX)
  printf( "%d\n" , VAR(abc) );
  return 0;
}

Even though it looks redundant, it's not.

Cataclinal answered 20/11, 2009 at 1:6 Comment(3)
It's a bit too late for me to try and understand the Standardese for 6.10.3.3 The ## operator, but it explains why somewhere there. ( pdf @ open-std.org/JTC1/sc22/wg14/www/docs/n1401.pdf )Veracity
Because the replacement list of a macro is not itself subject to macro-replacement before its parameters are replaced and # and ## operators applied. So in the questioner's code, def_##SUFFIX is replaced with def_SUFFIX before any opportunity to replace SUFFIX with ghi. In caf's code, when suffix is replaced by SUFFIX in VAR2, the argument is first subject to macro expansion (6.10.3.1/1). The result is VAR3(abc,ghi), which yields abc_def_ghi. Note that VAR3(abc,SUFFIX) would still give abc_def_SUFFIX, because parameters following ## are not expanded (also 6.10.2.1/1).Carpentaria
"(also 6.10.2.1/1)" - I mean "(also 6.10.3.1/1)".Carpentaria
S
7

The usual idiom for correctly using the stringizing (#) or token pasting (##) pre-processing operators is to use a 2nd level of indirection. (What are the applications of the ## preprocessor operator and gotchas to consider?).

#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)

#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)

Then:

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR(prefix) PASTE( prefix, PASTE( _def_, SUFFIX))
  printf( "%d\n" , VAR(abc) );
  return 0;
}

Should give you the results you're looking for.

Basically, what happens is that processing of the # and ## operators takes place before macro replacement. Then another round of macro replacement occurs. So if you want macros to be used along with those operations you have to use a 1st level that simply does the replacement - otherwise the stringizing or pasting happens first, and the macros aren't macros anymore- they're whatever the 1st round of stringizing/pasting produces.

To put it more directly - the first level of macro allows the macro parameters to be replaced, then the 2nd level of macro replacement does the stringify/token-pasting operation.

Stowell answered 20/11, 2009 at 8:27 Comment(1)
Wow, thank you, the STRINGIFY also solves another issue I've had.Higgler
L
0

This works with sufficient levels of indirection. While another answer is plenty adequate, I want offer this chunk of code as a demo:

#define SUFFIX ghi

#define VAR1(prefix) prefix##_def_##SUFFIX
VAR1(abc)

#define VAR2_(prefix, sfx) prefix##_def_##sfx
#define VAR2(prefix) VAR2_(prefix,SUFFIX)
VAR2(abc)

#define VAR3_(prefix, sfx) prefix##_def_##sfx
#define VAR3x(prefix,sfx) VAR3_(prefix,sfx)
#define VAR3(prefix) VAR3x(prefix,SUFFIX)
VAR3(abc)

Save this is a text file, x.c, and only preprocess it.

gcc -E x.c

Observe and ponder. I don't quite understand it entirely myself. Just spend two hours trying to get a macro using stringify to work. It is interesting to see that double indirection is sometimes needed.

Lenette answered 16/1, 2010 at 22:9 Comment(1)
I get abc_def_SUFFIX abc_def_SUFFIX abc_def_ghi Based on Steve's explanation, it sounds like it has to do with the order of macro replacement.Higgler

© 2022 - 2024 — McMap. All rights reserved.