Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
426 views
in Technique[技术] by (71.8m points)

c++ - 为什么要在宏中使用看似毫无意义的do-while和if-else语句?(Why use apparently meaningless do-while and if-else statements in macros?)

In many C/C++ macros I'm seeing the code of the macro wrapped in what seems like a meaningless do while loop.

(在许多C / C ++宏中,我看到了包裹在看起来毫无意义的do while循环中的宏代码。)

Here are examples.

(这是例子。)

#define FOO(X) do { f(X); g(X); } while (0)
#define FOO(X) if (1) { f(X); g(X); } else

I can't see what the do while is doing.

(我看不到什么do while做。)

Why not just write this without it?

(为什么不没有它就写这个呢?)

#define FOO(X) f(X); g(X)
  ask by jfm3 translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The do ... while and if ... else are there to make it so that a semicolon after your macro always means the same thing.

(do ... whileif ... else可以使之成为宏,因此宏后的分号始终表示同一意思。)

Let's say you had something like your second macro.

(假设您有类似第二个宏的内容。)

#define BAR(X) f(x); g(x)

Now if you were to use BAR(X);

(现在,如果您要使用BAR(X);)

in an if ... else statement, where the bodies of the if statement were not wrapped in curly brackets, you'd get a bad surprise.

(在if ... else语句中, if ... else语句的主体没有用大括号括起来,您会感到非常惊讶。)

if (corge)
  BAR(corge);
else
  gralt();

The above code would expand into

(上面的代码将扩展为)

if (corge)
  f(corge); g(corge);
else
  gralt();

which is syntactically incorrect, as the else is no longer associated with the if.

(这在语法上是不正确的,因为else不再与if关联。)

It doesn't help to wrap things in curly braces within the macro, because a semicolon after the braces is syntactically incorrect.

(在宏中用大括号将内容包装起来没有帮助,因为大括号后的分号在语法上是不正确的。)

if (corge)
  {f(corge); g(corge);};
else
  gralt();

There are two ways of fixing the problem.

(有两种解决问题的方法。)

The first is to use a comma to sequence statements within the macro without robbing it of its ability to act like an expression.

(第一种是使用逗号对宏内的语句进行排序,而不会使其失去像表达式一样的功能。)

#define BAR(X) f(X), g(X)

The above version of bar BAR expands the above code into what follows, which is syntactically correct.

(上面的bar BAR版本将上面的代码扩展为以下代码,这在语法上是正确的。)

if (corge)
  f(corge), g(corge);
else
  gralt();

This doesn't work if instead of f(X) you have a more complicated body of code that needs to go in its own block, say for example to declare local variables.

(如果您有一个更复杂的代码体需要放入其自己的代码块中,例如声明局部变量,则此方法不起作用,而不是f(X) 。)

In the most general case the solution is to use something like do ... while to cause the macro to be a single statement that takes a semicolon without confusion.

(在最一般的情况下,解决方案是使用诸如do ... while使宏成为包含分号且不会引起混淆的单个语句。)

#define BAR(X) do { 
  int i = f(X); 
  if (i > 4) g(i); 
} while (0)

You don't have to use do ... while , you could cook up something with if ... else as well, although when if ... else expands inside of an if ... else it leads to a " dangling else ", which could make an existing dangling else problem even harder to find, as in the following code.

(您不必使用do ... while ,你可以编造一些与if ... else为好,尽管当if ... else扩大了内部的if ... else ,就会造成“ 晃来晃去别的 ”,这将使现有悬而未决的其他问题更加难以发现,如以下代码所示。)

if (corge)
  if (1) { f(corge); g(corge); } else;
else
  gralt();

The point is to use up the semicolon in contexts where a dangling semicolon is erroneous.

(关键是在悬挂的分号错误的情况下用完分号。)

Of course, it could (and probably should) be argued at this point that it would be better to declare BAR as an actual function, not a macro.

(当然,在这一点上可以(也许应该)认为,最好将BAR声明为实际函数,而不是宏。)

In summary, the do ... while is there to work around the shortcomings of the C preprocessor.

(总而言之, do ... while可以解决C预处理程序的缺点。)

When those C style guides tell you to lay off the C preprocessor, this is the kind of thing they're worried about.

(当那些C风格指南告诉您解雇C预处理程序时,这是他们担心的事情。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...