do{}while(0) - macro safety

寵の児 提交于 2020-01-16 14:53:13

问题


We know that multiline macros have to be inclosed in a do while(0) loop for them to be safely included anywhere in the code.

For example this is 100% safe:

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

I would like to know if it is also safe to have a macro with a part of the code outside of the loop, and if it isn't, in what circumstances could problems occur.

#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)

Is there a safe way to achieve this, what would have to be changed or what rules should I follow if it isn't safe.


回答1:


It is not safe in many ways. First, if any variable called t already existed, it wouldn't compile.

Apart from that, you have to be careful with things like:

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

As it would be expanded to:

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

Note that the if body would be only a declaration because there are no braces for the if block.

Why don't you declare t inside the do block?




回答2:


Two cases I can think of. First, if there's already a variable t in current scope you will get either a multiple definitions or conflicting definitions in same scope error. Second, consider:

if (some_condition) swap(a,b);

will expand to:

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



回答3:


It would not be compile safe if a variable named t was anywhere else in that scope.




回答4:


There's a second problem in your macro besides the scope story. You forgot to put parenthesis to your macro variables, this can have some surprizing effects.

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

In C++ if you invoke the macro for instance with a ternary: swap(x?x:y, z) it would have a surprizing effect.

do
  {
  int t = x?x:y;
  x?x:y = z ;
  z = t;
  }
while(0)

as the ternary has lower priority than affectation, the second line will be interpreted as: x?x:(y = z);

There could be other surprizes, therefore as a rule:

Always put parenthesis around macro parameter, ALWAYS!

EDIT: This is the correct #define

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



回答5:


As your actual goal is to define t for access from outside the makro, you should declare it outside your makro. If your makro is something that can be used multiple times in one code block (like the swap you use as an example - you want to be able to swap multiple values), then you will get issues with multiple declarations of t.

Instead, you could do it like MFC with USES_CONVERSION and define another makro USES_SWAP that prepares all "global" data for your makro, and may be called only once in each code block, before any and all appearances of SWAP (so ideally at the beginning of the code block). Now you can swap things around as often as you like and still handle declaration of required variables in one makro.

Of course, the issue remains that the t declared in USES_SWAP will conflict with other ts, but that might just be a necessity if you can't find another way to do it. Which you should try to do ;) To reduce the possibility of this becoming an issue, you should consider a more specific name, such as swap_t or even SwapInternalVariable_t. The danger of someone declaring a variable with that name in normal code is pretty low.



来源:https://stackoverflow.com/questions/19116171/dowhile0-macro-safety

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!