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

时间:2009-10-09 13:26:18

标签: c++ visual-c++ gcc c-preprocessor

出于某种原因,我需要暂时禁用头文件中的某些宏,而#undef MACRONAME将使代码编译,但它将取消现有的宏。

有没有一种方法可以禁用它?

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

6 个答案:

答案 0 :(得分:82)

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

#pragma push_macro("MACRONAME")
#undef MACRONAME

// some actions

#pragma pop_macro("MACRONAME")

答案 1 :(得分:27)

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

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


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

如果宏没有在标题中定义,当然,在您重构代码以使它们位于标题中之前,您将陷入困境。

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

#undef

函数#define nonsense(a, b) b /\= a int (nonsense)(int a, int b) { return (a > b) ? a : b; } 被定义得很好,尽管它前面有宏。这是因为宏调用 - 对于类似函数的宏 - 必须紧跟一个左括号(给出或取出空格,可能包括注释)。在函数定义行中,'废话'之后的标记是一个紧密括号,因此它不是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; } 的伪造函数,并且是无意义的。并且没有宏观保护。

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

答案 2 :(得分:2)

宏使我的膝盖变弱,但最通用的解决方案是不是重构你的代码,这样你就不需要在同一个源文件中再次重新启用宏了?是不是可以将一些代码提取到一个单独的函数和一个单独的源文件中,您可以在其中取消违规宏。

答案 3 :(得分:1)

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

的事情
#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

答案 4 :(得分:0)

修改

你可能认为这很容易:

#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("MACR")

答案 5 :(得分:0)

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