Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I temporarily disable a macro expansion in C/C++?

For some reason I need to temporarily disable some macros in a header file and the #undef MACRONAME will make the code compile but it will undef the existing macro.

Is there a way of just disabling it?

I should mention that you do not really know the values of the macros and that I'm looking for a cross compiler solution (should work at least in GCC and MSVC).

like image 685
sorin Avatar asked Oct 09 '09 13:10

sorin


People also ask

Can you change macros in C?

You can't. Macros are expanded by the Preprocessor, which happens even before the code is compiled.

What does ## mean in macro in C?

The double-number-sign or token-pasting operator (##), which is sometimes called the merging or combining operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token, and therefore, can't be the first or last token in the macro definition.

Can a macro call itself in C?

You can't have recursive macros in C or C++.

How are macros expanded in C?

The LENGTH and BREADTH are called the macro templates. The values 10 and 20 are called macro expansions. When the program run and if the C preprocessor sees an instance of a macro within the program code, it will do the macro expansion. It replaces the macro template with the value of macro expansion.


2 Answers

In MSVC you could use push_macro pragma, GCC supports it for compatibility with Microsoft Windows compilers.

#pragma push_macro("MACRONAME") #undef MACRONAME  // some actions  #pragma pop_macro("MACRONAME") 
like image 62
Kirill V. Lyadvinsky Avatar answered Oct 08 '22 16:10

Kirill V. Lyadvinsky


Using just the facilities defined by Standard C (C89, C99 or C11), the only 'disable' mechanism is #undef.

The problem is there is no 're-enable' mechanism.


As others have pointed out, if the header file containing the macro definitions is structured so that it does not contain any typedef or enum declarations (these cannot be repeated; function and variable declarations can be repeated), then you could #undef the macro, do what you need without the macro in effect, and then re-include the header, possibly after undefining its protection against reinclusion.

If the macros are not defined in a header, of course, you are stuck until you refactor the code so that they are in a header.

One other trick is available - if the macros are function-like macros and not object-like macros.

#define nonsense(a, b)   b /\= a  int (nonsense)(int a, int b) {     return (a > b) ? a : b; } 

The function nonsense() is defined fine, despite the macro immediately before it. This is because a macro invocation - for a function-like macro - must be immediately followed by an open parenthesis (give or take white space, possibly including comments). In the function definition line, the token after 'nonsense' is a close parenthesis, so it is not an invocation of the nonsense macro.

Had the macro been an argument-less object-like macro, the trick would not work:

#define nonsense min  int (nonsense)(int a, int b) {     // Think about it - what is the function really called?     return (a > b) ? a : b; } 

This code defines a bogus function that's called min and is nonsensical. And there's no protection from the macro.

This is one of the reasons why the standard is careful to define which namespaces are reserved for 'The Implementation'. The Implementation is allowed to define macros for any purpose it desires or needs, of any type (function-like or object-like) it desires or needs, provided those names are reserved to the implementation. If you as a consumer of the services of The Implementation try to use or define a name reserved to the implementation, you must be aware that your code will probably break sooner or later, and that it will be your fault, not the fault of The Implementation.

like image 22
Jonathan Leffler Avatar answered Oct 08 '22 15:10

Jonathan Leffler