6

Imagine I want to #define a macro such that it is equal to the current value of another macro (if such a concept exists).

For example:

#include "def_a.h"  // defines macro A
#define B A

This defines B to be A. If A later changes definition (i.e., through a redefinition) the value of B also changes (because B expands to A at the point of use, which further expands to the new value of A).

What I'd like is some way to "bake in" the value of A into B so that B just expands to the value of A, not A itself.

For example:

#define A first
#define B BAKE_IN(A)
#undef A
#define A second
#define C BAKE_IN(A)
#undef A
#define A third

// here I want B to expand to first, and C to expand to second

Of course BAKE_IN is not a real thing, but I'm wondering if there is some way to achieve this effect.

Now, I didn't really say what should happen if A itself is defined in terms of other macros, but I'm OK both with "one level of expansion" (i.e., B gets the value of A is expanded, so further macros remain) and also "full expansion" (i.e., A is fully expanded, recursively, as it would be at a point of use).

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • Why you care too much about the steps of substitution and not about the final result. `#define B A` is sufficient to get the value of A but with two steps. Seeing the number of upvote did not get what did I miss here. I feel like you want to take the long road to rome. – Sabrina Feb 07 '17 at 17:46
  • 1
    Ok, I was not sure ... does someone know how to mark a question as duplicate without closing it? – David Ranieri Feb 07 '17 at 17:48
  • 1
    As far as I know, those are mutually exclusive. If a question is marked as duplicate, it gets closed with the little banner at the top directing you to the old question. – BeeOnRope Feb 07 '17 at 17:51
  • Can you elaborate more what you are trying to achieve ? assuming that I cannot C#. – Sabrina Feb 07 '17 at 17:55
  • 1
    @Sabrina - I want to `#include` a header file with specific macros defined/not-defined and then "capture" the value of a macro that this header file defines. Later, the macro that I captured from may change value, but I want the original value. – BeeOnRope Feb 07 '17 at 18:23
  • @Sabrina: That is no way related to C# – too honest for this site Feb 07 '17 at 18:29
  • @beeonarope: it is rarely good style to redefine a CPP macro, although it can be useful occasionally, for example with X-macros. What sort of value might your macro have? – rici Feb 07 '17 at 20:23
  • @rici - indeed, I do it pretty much never (this would be the my first use in recent memory). In fact, even though I do use X macros, I do with the "user form" that takes a function-as-macro as doesn't need redefinition (attributed to Andrei Alexandrescu at the [bottom of this article](http://www.drdobbs.com/cpp/the-x-macro/228700289#highlighter_616127), for example). This is one case where I thought it might be useful. Basically I'm [trying](http://stackoverflow.com/q/42093734/149138) to capture the value of the `assert` macro so I can re-use the implementation, after `#undef NDEBUG`. – BeeOnRope Feb 07 '17 at 22:14
  • ... ultimately though I don't think this approach could work even if `BAKE_IN` existed because I won't be able to include `assert.h` again with `NDEBUG` restored. Still I guess the question stands alone as somewhat useful to understand what is and isn't possible in the pre-processor. – BeeOnRope Feb 07 '17 at 22:15
  • 1
    @beeonrope: basically, this isn't possible with the preprocessor and even if it were, it wouldn't help with your use case. I put a suggestion about the assert use case as an answer to your other question; in this context, I'm going to stick with the answer I provided: you can freeze a macro only if it's value is an integer, and only with the black pp magic of boost-pp. – rici Feb 07 '17 at 23:26
  • Good enough for me, thanks. – BeeOnRope Feb 07 '17 at 23:27

2 Answers2

1

Macros are never replaced in the body of a #define directive, so there is no way to define a macro as the current value of another macro, except for the limited case of macros whose value is a constant arithmetic expression.

In the latter case, you can use BOOST_PP_ASSIGN_SLOT from the Boost preprocessor library. (Although most of the Boost libraries are C++-specific, the Boost preprocessor library works for both C and C++, and has no dependency on any other Boost component.)

rici
  • 234,347
  • 28
  • 237
  • 341
  • Your "exception" is none actually. And this is about C, not C++. – too honest for this site Feb 07 '17 at 17:32
  • 1
    @olaf: the boost preprocessor library works in both C and C++. – rici Feb 07 '17 at 18:03
  • @Olaf - does the underlying technique `BOOST_PP_ASSIGN_SLOT` uses work in C then, or are the preprocessor rules different? – BeeOnRope Feb 07 '17 at 18:24
  • @BeeOnRope: Boost is a C++ library. And it cannot change how cpp works. – too honest for this site Feb 07 '17 at 18:27
  • @olaf: boost-pp is not a c++ library. It is true that it does not change how cpp works -- but it has lots of tricks to make it do things you might not expect are possible. – rici Feb 07 '17 at 19:19
  • @rici: Ok, until then I assumed it was part of boost, which **is** C++ only. However, it might provide help for OP, but can't do what he asks for. So we have an XY-problem. – too honest for this site Feb 07 '17 at 19:59
  • @olaf: i don't know whether OP could use a numeric-only solution but perhaps other programmers who stumble upon this question have a problem which the `BOOST_PP_ASSIGN_SLOT` macro can solve. That's the reason I mentioned it rather than just saying "No, you can't do that". – rici Feb 07 '17 at 20:21
  • Although in my case I wasn't using a constant expression, this is exactly the kind of knowledge I'll stash away for future use, so it is very useful to me. Thanks @rici – BeeOnRope Feb 07 '17 at 23:28
1

I don't think there is a clean solution. The closest thing that I found is to preserve "stringified" values within char arrays:

#include <stdio.h>

#define BAKE_IN(X, id) BAKE_IN_REAL(X ## _, X, id)
#define BAKE_IN_REAL(X, Y, id) static const char X ## id[] = #Y;
#define BAKE_OUT(X, id) X ## _ ## id

#define A first
BAKE_IN(A, 1)
#define B BAKE_OUT(A, 1)
#undef A

#define A second
BAKE_IN(A, 2)
#define C BAKE_OUT(A, 2)
#undef A

int main(void)
{
    printf("%s\n", B); // prints "first"
    printf("%s\n", C); // prints "second"
    return 0;
}

The idea is that BAKE_IN macro declares object named as e.g. A_1, which holds the current expansion of A.

There are two major limitations:

  • Every pair of BAKE_IN and BAKE_OUT needs unique id
  • The expansion is only available in "stringified" form
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Thanks! This is quite useful when you need a string version of the macro, which is actually the case for some type of diagnostics, so I'll probably use this in the future. I accepted the other answer in this case because it was more directly applicable (since I definitely don't need a stringified form for my use case), but this is a good contribution. – BeeOnRope Feb 07 '17 at 23:32