The do ... while
and if ... else
are there to make it so that a semicolon after your macro always means the same thing.
(do ... while
和if ... 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预处理程序时,这是他们担心的事情。)