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

发布于 2024-08-07 01:06:03 字数 164 浏览 4 评论 0原文

由于某种原因,我需要暂时禁用头文件中的某些宏,并且 #undef MACRONAME 将使代码编译,但会取消现有宏的定义。

有没有办法禁用它?

我应该提到,您并不真正知道宏的值,并且我正在寻找交叉编译器解决方案(至少应该在 GCC 和 MSVC 中工作)。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

戒ㄋ 2024-08-14 01:06:03

在 MSVC 中,您可以使用 push_macropragma,GCC 支持以实现兼容性与 Microsoft Windows 编译器。

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")

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")
断肠人 2024-08-14 01:06:03

仅使用标准 C(C89、C99 或 C11)定义的功能,唯一的“禁用”机制是#undef

问题是没有“重新启用”机制。


正如其他人指出的那样,如果包含宏定义的头文件的结构使其不包含任何 typedef 或 enum 声明(这些声明不能重复;函数和变量声明可以重复),那么您可以 #undef 宏,在宏不生效的情况下执行您需要的操作,然后重新包含标头(可能是在取消定义其防止重新包含的保护之后)。

当然,如果宏没有在标头中定义,您就会陷入困境,直到您重构代码以使它们位于标头中。

另一种技巧是可用的 - 如果宏是类似函数的宏而不是类似对象的宏。

#define nonsense(a, b)   b /\= a

int (nonsense)(int a, int b)
{
    return (a > b) ? a : b;
}

函数 nonsense() 定义得很好,尽管它前面有宏。这是因为宏调用(对于类似函数的宏)必须紧跟一个左括号(给予或保留空格,可能包括注释)。在函数定义行中,“nonsense”后面的标记是一个右括号,因此它不是对 nonsense 宏的调用。

如果宏是一个无参数的类似对象的宏,那么这个技巧就不起作用:

#define nonsense min

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

这段代码定义了一个名为 min 的虚假函数,并且是无意义的。而且没有宏的保护。

这是该标准谨慎定义为“实现”保留哪些命名空间的原因之一。允许实现为其期望或需要的任何目的、其期望或需要的任何类型(类函数或类对象)定义宏,前提是这些名称保留给实现。如果您作为 The Implementing 服务的使用者尝试使用或定义为实现保留的名称,您必须意识到您的代码迟早会崩溃,并且这将是您的错误,而不是 The Implementing 的错误。执行。

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.

稀香 2024-08-14 01:06:03

宏让我的膝盖发软,但是最通用的解决方案不是重组代码,这样就不需要在同一个源文件中再次重新启用宏吗?难道不能将一些代码提取到一个单独的函数和一个单独的源文件中,您可以在其中取消定义有问题的宏吗?

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.

撑一把青伞 2024-08-14 01:06:03

这些宏来自某个头文件,因此您应该有权访问它们的值。然后你可以做类似的事情

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

// Do things with FOO

#undef FOO

// do things without FOO

#include <foo.h> // reenable FOO

你的标题应该沿着这些线设计

#ifndef FOO
#define FOO do_something(x,y)
#endif

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
歌入人心 2024-08-14 01:06:03

C/C++ 语言中类函数宏的调用有特定的规则。
类似函数的宏必须按以下方式调用:

  1. 宏名称
  2. 左括号
  3. 每个参数用一个标记用逗号分隔

此列表中的每个标记都可以用空格分隔(即实际的空格和逗号)


通过一个技巧,您可以“禁用预处理器机制”,违反了类似函数的宏调用的规则,但仍处于函数调用机制的规则之内......

#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;
}

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;
}
迷你仙 2024-08-14 01:06:03

编辑:

您可能认为这很简单:

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

// do what you want with macro

#ifdef DISABLED_macro
#define macro DISABLED_macro
#endif

但事实并非如此(如下面的示例所示)!

#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;
}

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

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

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")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文