48

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).

a3f
  • 8,517
  • 1
  • 41
  • 46
sorin
  • 161,544
  • 178
  • 535
  • 806
  • 2
    I suppose you have a convincing reason for actually having ended up in this macro mess? I couldn't think of one here... – sbi Oct 09 '09 at 14:09

6 Answers6

110

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")
Community
  • 1
  • 1
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • 21
    Nice to know that exists, and so good answer, but that's horrifying. – Phil Miller Oct 10 '09 at 21:18
  • 5
    This is why people keep telling us things like *macros are evil*. Sooner or later some one is going to create a macro called `new` that does something stupid... – John Leidegren Mar 25 '13 at 15:53
  • 1
    @JohnLeidegren well, we are half-way there now. [**Example of a misconstrued "evil" macro**](http://stackoverflow.com/q/18167990/319204). – TheCodeArtist Aug 11 '13 at 03:08
  • 1
    Also works in clang. Ugly, but helps work around naming conflicts caused by libraries out of your control. – Kekoa Aug 29 '13 at 05:06
  • Someone already created a macro called `new`! That's cpputest: `#define new new(__FILE__, __LINE__)` And now I can't use placement new in tests... – EvgEnZh Oct 22 '20 at 14:35
32

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

Macros make my knees go weak, but wouldn't the most universal solution be to restructure your code so that you wouldn't need to reenable the macro again in the same source file? Wouldn't it be possible to extract some code into a separate function and a separate source file where you can undef the offending macro.

UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • Sorry but sometimes you cannot modify the code to workaround this issue. – sorin Oct 09 '09 at 15:19
  • I suppose then, looking at the other answers, the only way to "reenable" macros in the general case is to copy their original definition. – UncleBens Oct 09 '09 at 15:46
1

The macros come from some header file, so you should have access to their values. You can then do something like

#include <foo.h> // declares macro FOO

// Do things with FOO

#undef FOO

// do things without FOO

#include <foo.h> // reenable FOO

Your header should then be designed along these lines

#ifndef FOO
#define FOO do_something(x,y)
#endif
Wernsey
  • 5,411
  • 22
  • 38
  • 4
    Make sure you don't have other things which are not macros you're enabling/disabling in that header file or else there will be issues with redeclaration. – Andrew Song Oct 09 '09 at 13:39
  • 7
    Also make sure that `` does not include the mantra `#ifndef FOO_H_INCLUDED / #define FOO_H_INCLUDED / ... / #endif` to protect against reinclusion. – Jonathan Leffler Oct 09 '09 at 13:45
  • 2
    Re-including header files is likely to cause other problems unless the header files were specifically designed to be used this way. – Stephen C. Steel Oct 09 '09 at 14:31
  • Another reason why this is not acceptable is because it can happen not even to know where this is defined. Also, reincluding the file most probably would not work. – sorin Oct 09 '09 at 15:17
1

EDIT:

You may think that it's that easy:

#ifdef macro
#define DISABLED_macro macro
#undef macro
#endif

// do what you want with macro

#ifdef DISABLED_macro
#define macro DISABLED_macro
#endif

But it's not (like the following example demonstrates)!

#include <iostream>
#include <limits>

#include <windows.h>

#ifdef max
#define DISABLED_max max
#undef max
#endif

int main()
{
    std::cout << std::numeric_limits<unsigned long>::max() << std::endl;

#ifdef DISABLED_max
#define max DISABLED_max
#endif

    std::cout << max(15,3) << std::endl;  // error C3861: "max": identifier not found
    return 0;
}

Using #undef on the macro and re-including the original header is also not likely to work, because of the header guards. So what's left is using the push_macro/pop_macro #pragma directives.

#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACRO")
Spooky
  • 2,966
  • 8
  • 27
  • 41
fmuecke
  • 8,708
  • 1
  • 20
  • 25
  • 1
    Except does it work? Doesn't it "restore" macro so, that it will hence-forth expand into "macro" (which is what I am seeing when I add missing parts)? May-be a full usage example? – UncleBens Oct 09 '09 at 13:57
1

There are specific rules for function-like macroses invokation in C/C++ language. The function-like macroses have to be invoked in the following way:

  1. Macros-name
  2. Left parethesis
  3. One token for each argument separated by commas

Each token in this list can be separared from another by whitespaces (i.e. actual whitespaces and commas)


With one trick you "disable preprocessor mechanism" with breaking rules for function-like macro invokation, but be still within a rules of function calling mechanism...

#include <iostream>
using namespace std;

inline const char* WHAT(){return "Hello from function";}

#define WHAT() "Hello from macro"

int main()
{
    cout << (*WHAT)() << "\n"; // use function
    cout << (WHAT)() << "\n";  // use function
    cout << WHAT () << "\n";   // use macro
    
    return 0;
}
Konstantin Burlachenko
  • 5,233
  • 2
  • 41
  • 40