Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C do{}while(0)-宏安全_C_Macros_Scope_Do While - Fatal编程技术网

C do{}while(0)-宏安全

C do{}while(0)-宏安全,c,macros,scope,do-while,C,Macros,Scope,Do While,我们知道,多行宏必须包含在do while(0)循环中,才能安全地包含在代码中的任何位置 例如,这是100%安全的: #define swap( a , b ) \ do \ { \ int t = a ; \ a = b ; \ b = t ; \ }

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

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

如果名为
t
的变量在该范围内的任何其他地方,那么编译就不安全。

我可以想到两种情况。首先,如果当前作用域中已经有一个变量
t
,那么在同一个作用域错误中将得到多个定义或冲突的定义。第二,考虑:

if (some_condition) swap(a,b);
将扩展到:

if (some_condition) int t;
do
{
    t = a;
    a = b;
    b = t;
} while (0);

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

除此之外,您还必须注意以下事项:

if (...)
    swap(a,b);
因为它将扩展到:

if (...)
    int t;
    do { ... } while(0);
请注意,if体将只是一个声明,因为if块没有大括号


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

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

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


当然,问题仍然是,在
USES\u SWAP
中声明的
t
将与其他
t
冲突,但如果找不到其他方法,这可能是必要的。你应该试着去做;)为了减少这成为一个问题的可能性,您应该考虑一个更具体的名称,例如<代码> SavaPyt < /Cube >,甚至<代码> SavaPialAlpababLyt 。在普通代码中使用该名称声明变量的危险性很低。

除了作用域之外,宏中还有第二个问题。您忘了在宏变量中加括号,这可能会产生一些意想不到的效果

#define swap( a , b )       \
        do                  \
        {                   \
            int t = a ;     \
            a = b ;         \
            b = t ;         \
        }                   \
        while(0)
在C++中,如果用三进制:<代码>交换(x?x:y,z)< /> >调用宏,它会有一个惊喜效果。

do
  {
  int t = x?x:y;
  x?x:y = z ;
  z = t;
  }
while(0)
由于三元的优先级低于矫揉造作,第二行将被解释为:
x?x:(y=z)

因此,通常会有其他惊喜:

始终在宏参数周围加括号,始终

编辑:这是正确的定义

#define swap( a , b )       \
        do                  \
        {                   \
            int t = (a) ;     \
            (a) = (b) ;         \
            (b) = t ;         \
        }                   \
        while(0)

我需要它在块外,然后将它包装在另一个do while块内,如下所示:do{int t;do{/*swap…*/}while(0);}while(0);我需要它在宏块之外:)啊好的。。。嗯,我想你必须接受这个,并坚持你原来的代码。是的,它会的。通常,您必须小心使用任何可以放置支架的说明(如果、虽然、for等)。但是如果你总是包含它们,应该不会有问题。if语句是唯一可能发生这种情况的地方吗?如果我在任何地方都使用If{}else{},那么我就不明白了?不,如果
If
被替换为
for
while
,你也会遇到同样的问题。switch语句可能有问题。如果您试图将它与短路逻辑运算符
|
&&
一起使用,您会遇到问题。为什么要这样做?我的编译器不允许我以任何方式将三元运算符放入
交换
宏中(需要左值)。我必须说我读过所有关于在宏变量周围加括号的内容,但从来没有读过关于宏参数的内容。你能提供一些信息(链接)吗?谢谢。可能会有误解,在
#define
中,每次出现宏参数都应该放在括号中,不是在调用点。我没有找到一个例子来说明C中的问题,这就是为什么我在
C++
中说,因为三元组与C中的优先级不同,并且允许它们作为
lvalue
。这并不意味着不会有其他问题。