0

我们知道多行宏必须包含在 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)

有没有一种安全的方法来实现这一点,必须改变什么或者如果它不安全我应该遵循什么规则。

4

5 回答 5

3

它在很多方面都不安全。首先,如果任何名为 t 的变量已经存在,它就不会编译。

除此之外,您必须小心以下事项:

if (...)
    swap(a,b);

因为它将扩展到:

if (...)
    int t;
    do { ... } while(0);

请注意,if 主体只是一个声明,因为 if 块没有大括号。

为什么不在 do 块内声明 t ?

于 2013-10-01T12:32:09.203 回答
2

我能想到的两个案例。首先,如果t当前范围内已经有一个变量,您将在同一范围内得到多个定义或冲突定义错误。其次,考虑:

if (some_condition) swap(a,b);

将扩展为:

if (some_condition) int t;
do
{
    t = a;
    a = b;
    b = t;
} while (0);
于 2013-10-01T12:31:43.893 回答
1

t如果一个名为的变量位于该范围内的任何其他位置,则它不会是编译安全的。

于 2013-10-01T12:29:32.053 回答
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)
于 2013-10-01T15:05:41.417 回答
0

由于您的实际目标是t从 makro 外部定义访问,因此您应该在 makro 外部声明它。如果您的 makro 可以在一个代码块中多次使用(例如swap您使用的示例 - 您希望能够交换多个值),那么您遇到t.

相反,您可以像 MFC 一样使用USES_CONVERSION并定义另一个 makro USES_SWAP,为您的 makro 准备所有“全局”数据,并且在每个代码块中只能调用一次,在任何和所有出现之前SWAP(理想情况下在代码的开头堵塞)。现在,您可以随心所欲地交换事物,并且仍然可以在一个 makro 中处理所需变量的声明。

当然,问题仍然是t声明的 inUSES_SWAP将与其他ts 冲突,但如果您找不到其他方法,这可能只是必要的。您应该尝试这样做;) 为了减少这成为问题的可能性,您应该考虑使用更具体的名称,例如swap_tor 甚至SwapInternalVariable_t. 在普通代码中使用该名称声明变量的危险非常低。

于 2013-10-01T13:00:06.997 回答