【问题标题】:Preserving preprocessor definitions [duplicate]保留预处理器定义
【发布时间】:2011-05-06 21:37:30
【问题描述】:

可能重复:
Can I redefine a C++ macro then define it back?

假设我有一些代码使用名称BLAH 作为变量。假设BLAH是许多标准头文件(定义为10)中常见的预处理器定义,那么如果我的文件包含在其中任何一个之后,代码就会中断,因为BLAH被转换为10;因此,我必须#undef BLAH。但其他标头也可能依赖于BLAH,因此我必须在我的标头完成后将BLAH 恢复为其原始值。有没有可能做这样的事情:

#ifdef BLAH
#define BLAH_OLD BLAH
#undef BLAH
#endif

... code ...

// restore BLAH to 10
#ifdef BLAH_OLD
#define BLAH BLAH_OLD
#end

?这当然行不通,因为 BLAH 没有扩展到 10。我试过做类似的事情

#define EXPAND_AGAIN(x) x
#define EXPAND(x) EXPAND_AGAIN(x)
#define BLAH_OLD EXPAND(BLAH)

但这也不起作用,因为 EXPAND 是按字面意思而不是展开的。我正在使用 MSVC 2008/2010,但如果该解决方案也适用于大多数其他编译器,那就太好了。

【问题讨论】:

  • 你考虑过改变你的变量命名吗?
  • 更改变量名;如果这是一个问题,您将在那里进行可怕的约定。不如说“这是我要解决的实际问题”,而不是“让我们说”。
  • 您确实意识到,几乎从一开始就有一个约定,即所有大写的标识符都保留给预处理器使用(以避免这样的事情)。

标签: c++ save c-preprocessor


【解决方案1】:

是的,因为您的编译器支持 push/pop 宏指令(visual c++、gcc、llvm 都可以):

#define BLAH 10

#pragma push_macro("BLAH")
#undef BLAH

#define BLAH 5

...

#pragma pop_macro("BLAH")

【讨论】:

  • 这似乎是 Microsoft 编译器特定的。
  • 抱歉,标准 C++ 没有定义 push_macro(Visual C++ 有这个 #pragma,但它不是标准 C++)。干杯,
  • 至少某些版本的 GCC 也支持它。
  • 我刚刚编辑了我的评论来解决这个问题,最新的 gcc/llvm 也支持它,但不确定它是什么时候添加到 gcc 中的。
  • clang 也可以处理这个问题。
【解决方案2】:

不幸的是,预处理器不支持定义堆栈。

Boost 预处理器库使预处理器可以做您从未想象过的事情(例如 C++98 中的有效可变参数宏),但受到预处理器固有限制的约束——所以,不能做,对不起。

唯一已知的中途补救措施是为宏保留ALL_UPPERCASE_IDENTIFIERS,并始终将它们用于宏。它在一定程度上减少了名称冲突问题。不幸的是,C 标准库定义了许多小写宏,或者允许它们的存在,例如assert,但他们只是少数。

从实际角度来看,主要问题在于 Windows 编程,其中 Microsoft 的 [windows.h] 标头定义了 zillions 个非大写宏,默认情况下包括 min 和 @ 987654325@与C++标准库冲突。

因此,对于 Windows C++ 编程,请始终在包含 [windows.h] 之前定义 NOMINMAX

干杯,

【讨论】:

  • 感谢NOMINMAX,但至少有#pragma push_macro
  • @Sergei:是的,#pragma push_macrothe accepted solution in the duplicate question。但正如我在对这个问题的另一个答案的评论中指出的那样,它在 2010 年是非标准的。我相信它仍然是非标准的,尽管它至少受到 Visual C++、g++ 和 clang 的支持。
【解决方案3】:

我曾经相信你尝试过的同样的技巧确实有效,就像我自己曾经使用过的一样。但我最终了解到它实际上根本不起作用。简单的答案是否定的,您不能保存定义的当前值、更改它,然后恢复旧值。预处理器根本不能那样工作。一旦定义了新值,旧值就消失了。

【讨论】:

    【解决方案4】:

    对我有用的一个技巧是在类中使用枚举。

    class foo
    {
    public:
      enum { blah = 10 } myenum;
    }
    

    那么你就可以使用

    foo:blah
    

    当您需要“10”时。

    因为它是类的一部分,所以 'blah' 的其他用法不会发生冲突,您可以保存所有定义和取消定义。

    【讨论】:

    • 什么? #define blah 0,破坏你的代码。
    • -1 表示通常不起作用的建议。如果“blah”已经被定义为预处理器宏,那么枚举定义很可能在语法上是错误的。通过的唯一可能性是当“blah”被定义为有效标识符时。干杯,
    • 用枚举替换宏,处理宏冲突的所有问题都消失了。它不会修复“推送”一个值。
    • 我认为这对例如 STL max 没有帮助。它几乎是一个函数,除了 Windows,它定义为一个宏(甚至在 VS2015/C++11 中)。见PRB: Using STL in Windows Program Can Cause Min/Max Conflicts
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 2021-12-29
    • 1970-01-01
    相关资源
    最近更新 更多