alexei
alexei

Reputation: 2321

How to rename a C preprocessor macro?

Consider a (read-only third-party) header lib.h with:

#define XYZ 42

In a source file, I want to use the word XYZ for an unrelated purpose, and do not want the substitution with 42. But, in the same source file, for other purposes, I also do want to access the value 42 from lib.h without hardcoding it. How do I rename the macro from XYZ to, say, LIB_XYZ?

The following does not work, because preprocessor wants XYZ at the time the LIB_XYZ substitution is made, but XYZ had been undefined:

#include "lib.h"
#define LIB_XYZ XYZ
#undef XYZ

Is there a way to trick the preprocessor into expanding LIB_XYZ to its final value before XYZ is lost?

Upvotes: 15

Views: 5483

Answers (4)

Kaz
Kaz

Reputation: 58667

A preprocessor symbol is a name. There is no preprocessing directive which changes the name itself, while preserving the contents. For instance, given either:

#define FOO 42

or

#define FOO(x, y)  x ## y (

There is no way to define a macro called BAR which has the same contents, without repeating these definitions. That is to say, there is no operation like:

#alias BAR FOO  // nonexistent fantasy macro-cloning preprocessor directive

Nor like this:

#rename BAR FOO // like #alias BAR FOO followed by #undef FOO

If we do this:

#define BAR FOO  // for the #define FOO 42 case

it's not an alias. Macro BAR is defined such that its replacement token sequence is the token FOO, and not 42. If the FOO macro disappears, then BAR loses its meaning.

Note also that C preprocessor macros cannot expand into preprocessing directives, so the following approach also will not work:

 // wrong:
 #define MACRO_DEFINER(NAME) \
   #define NAME 42

 MACRO_DEFINER(FOO) // hoping for #define FOO 42: no such luck
 MACRO_DEFINER(BAR) // hoping for #define BAR 42: likewise

I'm afraid that you have to take a few steps back to find an alternative strategy to whatever problem you're trying to solve. If you get stuck, create a new question about the actual problem.

There is always code generation: generating C or C++ at build time. Then any textual substitution or expansion you can dream of is possible, if you just tweak your generation system.

Any solution that involves #undef XYZ risks brekaing the functionality of the library header. The library might do something like this:

#define XYZ 42 #define macro(B) bloop(XYZ, B)

If we are using macro, then we break it if we redefine XYZ.

If the library is known for defining XYZ and we manage to redefine it successfully in code which uses that library, the situation will be confusing to future maintainers. "Oh, this XYZ is not actually that library one; this programmer just wanted an unrelated XYZ."

The best solution here is to stop wanting to use XYZ and find some other name. Adapt to the libraries you're using; don't clash with them.

Upvotes: 0

Craig Estey
Craig Estey

Reputation: 33631

If XYZ from lib.h is a number [or a constant of a variety], you could use an enum:

enum { LIB_XYZ = XYZ };
#undef XYZ

If XYZ is not the above, you have to create (e.g.) myxyz.c that does not include lib.h and use XYZ there (other files may include xyz.h)

The difference is that #define LIB_XYZ XYZ will not be resolved at that line, only when you use it later, as in:

foo(LIB_XYZ);

so that won't work because you've already #undef'ed the XYZ.

Upvotes: 4

5gon12eder
5gon12eder

Reputation: 25459

Not with the pre-processor, at least, not that I am aware of.

However, for simple constants with known type like in your example, there is a workaround.

#include <stdio.h>

// <xyz.h>

#define XYZ 42

// </xyz.h>

enum xyz_constants
{
  LIB_XYZ = XYZ,
};

#undef XYZ

#define XYZ 27

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, XYZ);
  return 0;
}

Not showing the fluff from stdio.h, this code is pre-processed to the following.

enum xyz_constants
{
  LIB_XYZ = 42,
};

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, 27);
  return 0;
}

You can extend this to some degree to other data types and certain function-like macros but there are of course limits.

Anyway, why do you need the particular identifier XYZ? Can't you use a different name for your macro?

Upvotes: 8

Cecilio Pardo
Cecilio Pardo

Reputation: 1717

Use another .c file, and assign the macro value to a global variable.

Upvotes: 0

Related Questions