如何暂时禁用C/ c++中的宏展开?

时间:2022-11-25 10:53:21

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.

出于某种原因,我需要临时禁用头文件中的一些宏,而#undef MACRONAME将使代码编译,但它将会对现有的宏进行undef。

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

我应该指出的是,您并不真正了解宏的值,我正在寻找一个交叉编译器解决方案(至少在GCC和MSVC中应该有效)。

5 个解决方案

#1


75  

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

在MSVC中,您可以使用push_macro pragma, GCC支持它与Microsoft Windows编译器兼容。

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")

#2


27  

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

使用标准C (C89、C99或C11)定义的工具,唯一的“禁用”机制是#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.

正如其他人所指出的,如果包含宏定义的头文件是结构化的,因此它不包含任何类型定义或枚举声明(这些声明不能重复;函数和变量声明可以被重复),然后您可以#undef宏,在不使用宏的情况下做您需要做的事情,然后重新包含header,可能是在不定义其对重新包含的保护之后。

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.

当然,如果在header中没有定义宏,那么在重构代码以使它们位于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.

这段代码定义了一个伪函数,叫做min,是无意义的。而且没有宏观的保护。

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.

这就是标准谨慎定义为“实现”保留哪些名称空间的原因之一。该实现允许为它希望或需要的任何目的(如功能或类似对象)定义宏,只要这些名称保留给实现。如果您是实现服务的使用者,尝试使用或定义为实现保留的名称,您必须知道您的代码迟早会崩溃,这将是您的错误,而不是实现的错误。

#3


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.

宏会让我崩溃,但最通用的解决方案不是重构代码,这样您就不需要在同一个源文件中重新启用宏了吗?难道不可能将一些代码提取到一个单独的函数和一个单独的源文件中,在这个文件中,您可以解除对违规宏的定义吗?

#4


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

#5


0  

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.

在宏上使用#undef并重新包含原始头也不太可能工作,因为头保护。剩下的就是使用push_macro/pop_macro #pragma指令。

#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACR")

#1


75  

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

在MSVC中,您可以使用push_macro pragma, GCC支持它与Microsoft Windows编译器兼容。

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")

#2


27  

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

使用标准C (C89、C99或C11)定义的工具,唯一的“禁用”机制是#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.

正如其他人所指出的,如果包含宏定义的头文件是结构化的,因此它不包含任何类型定义或枚举声明(这些声明不能重复;函数和变量声明可以被重复),然后您可以#undef宏,在不使用宏的情况下做您需要做的事情,然后重新包含header,可能是在不定义其对重新包含的保护之后。

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.

当然,如果在header中没有定义宏,那么在重构代码以使它们位于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.

这段代码定义了一个伪函数,叫做min,是无意义的。而且没有宏观的保护。

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.

这就是标准谨慎定义为“实现”保留哪些名称空间的原因之一。该实现允许为它希望或需要的任何目的(如功能或类似对象)定义宏,只要这些名称保留给实现。如果您是实现服务的使用者,尝试使用或定义为实现保留的名称,您必须知道您的代码迟早会崩溃,这将是您的错误,而不是实现的错误。

#3


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.

宏会让我崩溃,但最通用的解决方案不是重构代码,这样您就不需要在同一个源文件中重新启用宏了吗?难道不可能将一些代码提取到一个单独的函数和一个单独的源文件中,在这个文件中,您可以解除对违规宏的定义吗?

#4


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

#5


0  

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.

在宏上使用#undef并重新包含原始头也不太可能工作,因为头保护。剩下的就是使用push_macro/pop_macro #pragma指令。

#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACR")