Redefining or Changing MACro Value

Redefining or changing macro value

You can undefine it and define again:

#include <iostream>

#define AAA 13

int main()
{
#undef AAA
#define AAA 7
std::cout << AAA;
}

outputs: 7

Please note that statements that start with # are preprocessor directives that are taken care of before the code is even compiled. In this case, this constant AAA will be simply replaced by 7, i.e. it works just like a textual replacement with no additional checks of syntax, no type safety etc...

...which is main reason why you should avoid using macros and #defines where they can be replaced by static functions and variables :)


Why "textual replacement" ?

Look at this code:

#include <iostream>

#define AAA 13

void purePrint() {
std::cout << AAA;
}

void redefAndPrint() {
#undef AAA
#define AAA 7
std::cout << AAA;
}

int main()
{
#undef AAA
#define AAA 4
purePrint();
redefAndPrint();
purePrint();
}

preprocessor goes line by line from the top to the bottom, doing this:

  • ah, #define AAA 13, so when I hit AAA next time, I'll put there 13
  • look, purePrint uses AAA, I'm replacing it with 13
  • wait, now they tell me to use 7, so I'll stop using 13
  • so here in redefAndPrint() I'll put there 7

transforming the given code into this one:

#include <iostream>

void purePrint() {
std::cout << 13;
}

void redefAndPrint() {
std::cout << 7;
}

int main()
{
purePrint();
redefAndPrint();
purePrint();
}

which will output 13713 and the latest #define AAA 4 won't be used at all.

Can I redefine a macro with another #define directive?

Redefining a macro (when the redefintion is not the same) is a constraint violation. The constraint is spelled out in sectino 6.10.3p2 of the C standard:

An identifier currently defined as an object-like macro shall
not be redefined by another #define preprocessing directive unless
the second definition is an object-like macro definition and
the two replacement lists are identical.
Likewise, an
identifier currently defined as a function-like macro shall
not be redefined by another #define preprocessing directive
unless the second definition is a function-like macro
definition that has the same number and spelling of parameters,
and the two replacement lists are identical.

And section 4p2 states the following about constraint violations:

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside
of a constraint or runtime-constraint is violated, the
behavior is undefined.
Undefined behavior is otherwise indicated
in this International Standard by the words ‘‘undefined
behavior’’ or by the omission of any explicit definition of
behavior. There is no difference in emphasis among these three; they
all describe ‘‘behavior that is undefined’’.

So redefining a macro invokes undefined behavior. You must use #undef if you want to redefine the macro.

How to redefine a macro using its previous definition

Self-referential macros do not work at all:

http://gcc.gnu.org/onlinedocs/cpp/Self_002dReferential-Macros.html#Self_002dReferential-Macros

If you're working on C++ you can obtain the same results with template functions and namespaces:

template <typename T> void xxx( x ) {
printf( "%s\n", x );
}

namespace my_namespace {

template <typename T> void xxx( T x ) {
::xxx(x);
::yyy(x);
}

}

What happens when you redefine a macro?

From the standard (draft) [cpp.replace] §2:

An identifier currently defined as an object-like macro (see below) may be redefined by another #define
preprocessing directive provided that the second definition is an object-like macro definition and the two
replacement lists are identical, otherwise the program is ill-formed. [...]


What happens when you redefine a macro?

When the new definition is different, your program is ill-formed. The compiler is required to show you a diagnostic message (a warning, or an error). The behaviour of an ill-formed program is not defined by the standard. The compiler is free to refuse compiling the program.

What will my_value be 3 or 45?

Whatever your pre-processor/compiler chooses. Or the compiler could refuse to compile it.


Technically, the program would become well-formed if you first undefined the macro. Then the defined value would obviously be the newly defined. However, I do not recommend this, because you can then easily break other rules depending on the order of inclusion of headers in multiple translation units.

Most likely, the two macros are supposed to be separate entities, and there are different files that expect the definition from one header, and not the other. The correct solution is to give each a unique name by renaming one, and change the dependant files to use the new name. Figuring out which files use which definition is may be a challenge. While you're at it, you may want to replace the macro with a constexpr variable.

Can I redefine a C++ macro then define it back?

As greyfade pointed out, your ___T___ trick doesn't work because the preprocessor is a pretty simple creature. An alternative approach is to use pragma directives:

 // juice includes here
#pragma push_macro("T")
#undef T
// include boost headers here
#pragma pop_macro("T")

That should work in MSVC++ and GCC has added support for pop_macro and push_macro for compatibility with it. Technically it is implementation-dependent though, but I don't think there's a standard way of temporarily suppressing the definition.

Why macro redefined error occurs only when value is different and Macro name is same?

They have the same name, so it is the same macro you're changing. But it is present in two files. As long as the value is the same there is no problem, but when you change the value the compiler can't figure out which one is the "right" one. This causes a conflict. Try not to define a value in more than one file. But if necessary put

#ifndef RATES_BALANCE_SCALER
#define RATES_BALANCE_SCALER 1000000
#endif

so that, if the value is already defined, it will not be redefined.

edit: This will cause the value to not change, if the third party macro is defined first! If you need the value, name it something different

How is value of macro getting change

Preprocessing is done before the actual C code compilation. It simply textually replaces the token NUM with token var.

So after the preprocessing your function is:

int main()
{
int var;
printf("write the value of var:\n");
scanf("%d", &var);

printf("The value of S is %d\n", var);
var = var + 1; //changing the value of variable 'var'
printf("New value of S is %d", var);
return 0;
}

This main function is being compiled. As you see the NUM has been replaced with var and the result is obvious.

Redefining macros with old contents / Making a file include counter

Is there a way to expand the macros when the macro is defined.

Yes. But beware... using this as a means of generating unique symbols may cause unexpected linker issues if your symbols have external linkage.

Overview

The key problem here is that macros are not variables. With variables, if I have x=3*3; y=x;, then I'm assigning the value of x to y. With macros, if I have #define PPX 3*3 #define PPY PPX, then I'm literally assigning PPX to PPY. If I then evaluate PPY, it expands to PPX, and then to 3*3 but only because PPX is currently defined as 3*3.

However, there is a way around this. The preprocessor can evaluate expressions; it just uses conditional directives to do so. But due to the fact that this can branch, we can define macros conditionally based on PPX's value (as opposed to its replacement list). For example:

#if (PPX)%10==9
# define PPX_DIGIT_0 9
#elif (PPX)%10==8
# define PPX_DIGIT_0 8
...

So whereas PPY critically relies on PPX being defined as 3*3 to expand to 3*3; since PPX_DIGIT_0 is literally defined as 9, PPX can be undefined, and PPX_DIGIT_0 will still expand to 9. Note also that the conditional played a role in reducing the expression; (3*3)%10 is just equal to 9, causing the 9 branch to be hit. That loses the expression per se, picking up just the evaluation... which we want.

That's the idea. In practice, this requires a fair amount of code; fortunately, boost's preprocessor library already has it done for you, so here are two approaches using boost:

Approach 1: Using Boost Slots

include_counter.h:

#include <boost/preprocessor/slot/slot.hpp>
#if !(INCLUDE_COUNT)
# define INCLUDE_COUNT 0
# define BOOST_PP_VALUE INCLUDE_COUNT
# include BOOST_PP_ASSIGN_SLOT(1)
# undef BOOST_PP_VALUE
# undef INCLUDE_COUNT
# define INCLUDE_COUNT BOOST_PP_SLOT(1)
#endif
#define BOOST_PP_VALUE 1+INCLUDE_COUNT
#include BOOST_PP_ASSIGN_SLOT(1)

Boost slots evaluate macros and store their results using special internal states. You get 5 slots (code above is using slot 1), so you can store 5 numbers. This solution just initializes the slot to 0 before incrementing on the first include, then essentially just increments.

Approach 2: Use Boost Counter

include_counter.h:

#if !(INCLUDE_COUNT)
# include <boost/preprocessor/slot/counter.hpp>
# define INCLUDE_COUNT BOOST_PP_COUNTER
#endif
#include BOOST_PP_UPDATE_COUNTER()

Same idea, though it "consumes" boost counter.

Both boost solutions take the approach I just described. There's also a boost increment macro; feel free to ignore that, since (a) you're evaluating anyway, and (b) boost increment is a bit whimpy (with its maximum limit of 256).

You can also roll your own solution. But when you're done, it's going to look similar to boost's solution anyway. (The advantage is, your new "slot" will be independent of boost counter and boost slots).



Related Topics



Leave a reply



Submit