保留预处理器定义

23

可能是重复的问题:
我能重新定义C ++宏然后再次定义吗?

假设我有一些使用变量名 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,但如果解决方案能够在大多数其他编译器上工作,那将是可爱的。


3
你是否考虑过更改变量的命名? - Paul Sonier
更改你的变量名,如果这是一个问题的话,那么你使用的命名规范真的很糟糕。而且你可以考虑用“这是我要解决的实际问题”代替“假设”。 - GManNickG
1
你应该意识到,从时间的开始几乎就有一个惯例,即全大写的标识符被预处理器保留使用(以避免出现这样的情况)。 - Martin York
4个回答

37

是的,只要你的编译器支持push/pop宏指令(Visual C++、GCC和LLVM都支持):

#define BLAH 10

#pragma push_macro("BLAH")
#undef BLAH

#define BLAH 5

...

#pragma pop_macro("BLAH")

1
这似乎是特定于Microsoft编译器的。 - user405725
1
抱歉,标准的C++并没有定义push_macro(Visual C++中有该#pragma,但它不是标准的C++)。祝好! - Cheers and hth. - Alf
至少GCC的某些版本也支持它。 - Steve Fallows
我刚刚编辑了我的评论来解决这个问题,最新的gcc/llvm也支持它,但不确定它是何时被添加到gcc中的。 - yonilevy
clang 也可以处理这个。 - xdevs23

4

很遗憾,预处理器不支持定义的堆栈。

Boost预处理器库使预处理器能够执行您无法想象的操作(例如在C++98中有效地使用可变参数宏),但受到预处理器固有限制的束缚 - 所以,不行,抱歉。

已知的唯一半途解决方法是将ALL_UPPERCASE_IDENTIFIERS保留为宏,并始终将其用于宏。这在某种程度上减少了名称冲突问题。不幸的是,C标准库定义了许多小写字母宏,或允许它们存在,例如assert,但它们只有很少。

从实际角度来看,主要问题在于Windows编程,在那里Microsoft的[windows.h]头文件定义了大量的非大写字母宏,包括默认情况下与C ++标准库冲突的minmax

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

祝好!


感谢NOMINMAX,但至少有#pragma push_macro - Sergei Krivonos
@Sergei:是的,#pragma push_macro重复问题中被接受的解决方案。但正如我在对这个问题的另一个答案的评论中指出的那样,它在2010年是非标准的。我认为它仍然是非标准的,尽管至少被Visual C++、g++和clang支持。 - Cheers and hth. - Alf

0

我曾经相信你尝试的同样方法会起作用,因为我自己曾经使用过它。但最终我发现这根本不起作用。简单的答案是不行,你不能保存一个定义的当前值,改变它,然后恢复旧值。预处理器就是不按照那种方式工作的。一旦你定义了一个新值,旧值就消失了。


-3
一个对我有用的技巧是在类中使用枚举。
class foo
{
public:
  enum { blah = 10 } myenum;
}

然后你可以直接使用

foo:blah

当你需要 '10' 时。

由于它是类的一部分,因此对 'blah' 的其他用途不会冲突,并且您可以节省所有的定义和未定义操作。


1
什么?#define blah 0会破坏你的代码。 - GManNickG
-1 通常不起作用的建议。如果“blah”已经被定义为预处理器宏,那么枚举定义很可能会在语法上出现问题。唯一能通过的可能性是当“blah”被定义为有效标识符时。干杯! - Cheers and hth. - Alf
用枚举替换宏,所有处理宏冲突的问题都会消失。但这并不能解决“推送”值的问题。 - Jay
1
我认为这不会对STL的max函数有所帮助。在Windows中,它几乎是一个函数,除了定义为宏(即使在VS2015/C++11中也是如此)。请参阅PRB:在Windows程序中使用STL可能会导致Min/Max冲突 - jww

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接