如何暂时禁用 C/C++ 中的宏扩展?
由于某种原因,我需要暂时禁用头文件中的某些宏,并且 #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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在 MSVC 中,您可以使用
push_macro
pragma,GCC 支持以实现兼容性与 Microsoft Windows 编译器。
In MSVC you could use
push_macro
pragma, GCC supports it for compatibility with Microsoft Windows compilers.仅使用标准 C(C89、C99 或 C11)定义的功能,唯一的“禁用”机制是
#undef
。问题是没有“重新启用”机制。
正如其他人指出的那样,如果包含宏定义的头文件的结构使其不包含任何 typedef 或 enum 声明(这些声明不能重复;函数和变量声明可以重复),那么您可以 #undef 宏,在宏不生效的情况下执行您需要的操作,然后重新包含标头(可能是在取消定义其防止重新包含的保护之后)。
当然,如果宏没有在标头中定义,您就会陷入困境,直到您重构代码以使它们位于标头中。
另一种技巧是可用的 - 如果宏是类似函数的宏而不是类似对象的宏。
函数
nonsense()
定义得很好,尽管它前面有宏。这是因为宏调用(对于类似函数的宏)必须紧跟一个左括号(给予或保留空格,可能包括注释)。在函数定义行中,“nonsense”后面的标记是一个右括号,因此它不是对nonsense
宏的调用。如果宏是一个无参数的类似对象的宏,那么这个技巧就不起作用:
这段代码定义了一个名为
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.
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 thenonsense
macro.Had the macro been an argument-less object-like macro, the trick would not work:
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.
宏让我的膝盖发软,但是最通用的解决方案不是重组代码,这样就不需要在同一个源文件中再次重新启用宏吗?难道不能将一些代码提取到一个单独的函数和一个单独的源文件中,您可以在其中取消定义有问题的宏吗?
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.
这些宏来自某个头文件,因此您应该有权访问它们的值。然后你可以做类似的事情
你的标题应该沿着这些线设计
The macros come from some header file, so you should have access to their values. You can then do something like
Your header should then be designed along these lines
C/C++ 语言中类函数宏的调用有特定的规则。
类似函数的宏必须按以下方式调用:
此列表中的每个标记都可以用空格分隔(即实际的空格和逗号)
通过一个技巧,您可以“禁用预处理器机制”,违反了类似函数的宏调用的规则,但仍处于函数调用机制的规则之内......
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:
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...
编辑:
您可能认为这很简单:
但事实并非如此(如下面的示例所示)!
由于头保护的原因,在宏上使用#undef 并重新包含原始头也不太可能起作用。
所以剩下的就是使用
push_macro/pop_macro #pragma
指令。EDIT:
You may think that it's that easy:
But it's not (like the following example demonstrates)!
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.