我们知道多行宏必须在do while(0)循环中包含,以便它们安全地包含在代码中的任何位置。
例如,这是100%安全的:
#define swap( a , b ) \
do \
{ \
int t = a ; \
a = b ; \
b = t ; \
} \
while(0)
我想知道在循环外部有一部分代码的宏是否也是安全的,如果不是,在什么情况下会出现问题。
#define swap( a , b ) \
int t ; \ //should be in the same scope where the macro was called and before the loop
do \
{ \
t = a ; \
a = b ; \
b = t ; \
} \
while(0)
是否有一种安全的方法可以实现这一点,如果不安全,我必须更改哪些规则或遵循哪些规则。
答案 0 :(得分:3)
在许多方面都不安全。首先,如果已经存在任何名为t的变量,则无法编译。
除此之外,你必须小心:
if (...)
swap(a,b);
因为它将扩展为:
if (...)
int t;
do { ... } while(0);
请注意,if主体只是一个声明,因为if块没有大括号。
为什么不在do块中声明?
答案 1 :(得分:2)
我能想到的两个案例。首先,如果当前范围中已存在变量t
,则会在同一范围错误中获得多个定义或冲突定义。其次,考虑一下:
if (some_condition) swap(a,b);
将扩展为:
if (some_condition) int t;
do
{
t = a;
a = b;
b = t;
} while (0);
答案 2 :(得分:1)
如果名为t
的变量在该范围内的任何其他位置,则编译安全。
答案 3 :(得分:1)
除了范围故事之外,你的宏还有第二个问题。你忘了在你的宏变量中加上括号,这可能会产生一些惊人的效果。
#define swap( a , b ) \
do \
{ \
int t = a ; \
a = b ; \
b = t ; \
} \
while(0)
在C ++中,如果您使用三元组swap(x?x:y, z)
调用宏,则会产生令人惊讶的效果。
do
{
int t = x?x:y;
x?x:y = z ;
z = t;
}
while(0)
由于三元的优先级低于做作,第二行将被解释为:
x?x:(y = z);
可能还有其他的惊喜,因此通常:
始终将括号括在宏参数周围,总是!
编辑:这是正确的#define
#define swap( a , b ) \
do \
{ \
int t = (a) ; \
(a) = (b) ; \
(b) = t ; \
} \
while(0)
答案 4 :(得分:0)
由于您的实际目标是定义t
以便从makro外部进行访问,因此您应该在makro之外声明它。如果您的makro可以在一个代码块中多次使用(例如您用作示例的swap
- 您希望能够交换多个值),那么将获得t
的多个声明的问题。
相反,您可以像使用USES_CONVERSION
的MFC一样执行此操作,并定义另一个为您的makro准备所有“全局”数据的makro USES_SWAP
,并且可以在每个代码块中调用一次,之后以及SWAP
的所有外观(理想情况下,在代码块的开头)。现在你可以随意交换东西,并且仍然可以在一个makro中处理所需变量的声明。
当然,问题仍然是t
中声明的USES_SWAP
会与其他t
发生冲突,但如果您找不到另一种方式,那么这可能是必要的做到这一点。你应该尝试做什么;)为了减少这个问题的可能性,你应该考虑一个更具体的名称,例如swap_t
甚至SwapInternalVariable_t
。在普通代码中有人用该名称声明变量的危险性非常低。