I want to invoke multi-line macro in circulation to break/continue it.
If I use "do{...}while(0)" in multi-line macro definition, break/continue is only effect on "do {...}while(0)", not the circulation who invoke this macro. So I consider using "if(1){...}" in multi-macro definition.
#define EXIT_CIRCULATION() \
if(1){ \
break; \
}
void func(){
while(1){
...
EXIT_CIRCULATION();
...
}
}
But I doubt wheather it is a good way to use "if(1){...}" in macro definition, because I can not find any example in internet.
Thanks!
if you code something like
if (somecondition)
EXIT_CIRCULATION();
else
break;
then the expansion of your macro won't behave as you intuitively expect. The else
would apply to your if (1)
and will never happen.
The whole idea behind this trick is to find a way to create a multi-line (ie compound) statement that also incorporates a terminating ;
as its integral part. That will give you the opportunity to use ;
after your macro invocation without inadvertently introducing an empty statement.
The ordinary compound statement in { ... }
doesn't work because it does not end in ;
. The only multi-line statement in C/C++ that ends in ;
is do/while
. There's no other statements in C/C++ grammar that would satisfy this requirement. (This is an inaccurate claim, see my "PS" below)
In all other cases (including your if (1) {...}
) the ;
after the macro invocation will be seen as an additional independent standalone empty statement. This will make it impossible to write a ;
after your macro invocation when it is used in contexts requiring exactly one statement (like true branch of if-else
or the body of do/while
cycle).
For example, if you define
#define A() if (1) {}
then this code will not compile
do
A();
while (1);
because it will be replaced with
do
if (1) {}; /* <- two statements, not one */
while (1);
and that is actually two statements between do
and while
. Specifying two statements between do
and while
without wrapping them into {}
is syntax error.
PS Correction: The claim I make above about do/while
being the only viable variant is incorrect . In @Michael Burr's answer you can see another suitable variant, which is using the else ((void) 0)
trick for the same purpose. However, the main principle remains the same.
Here's a macro that I believe will safely do what you want:
#define EXIT_CIRCULATION() \
if (1) { \
/* some statements */ \
break; \
} \
else \
do {} while (0)
The fact that the if
here is matched with an else
means that the macro is safe to use inside another if
, and since the else
clause is a do-nothing do
/ while
statement that provides the similar properties to wrapping a multi-line macro in a do
/ while
. Such as the macro will need to be terminated by a semicolon as if it were a normal statement; forgetting the semicolon will result in a syntax error. And it plays nice inside another if
or else
clause.
And most importantly for you (I think), the break
statement isn't swallowed by the macro - it will break out the loop the macro is used in.
Whether that's a good idea or not is something else entirely. Many programmers don't like flow-control statements to be hidden within a macro (unless the flow of control is entirely within the macro unit).
Here it is in action:
#include<stdio.h>
#include<stdlib.h>
#define EXIT_CIRCULATION() \
if (1) { \
puts("done."); \
break; \
} \
else \
do {} while (0)
int main()
{
int i = 0;
for (i = 0; i < 10; ++i) {
if (i > 4)
EXIT_CIRCULATION();
else
puts("working...");
}
printf("i == %d\n", i);
return 0;
}
output:
working...
working...
working...
working...
working...
done.
i == 5
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.