Path: csiph.com!news.swapon.de!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: how to make a macro work as a single line if stmt without braces Date: Sat, 21 Sep 2024 15:55:12 -0700 Organization: None to speak of Lines: 63 Message-ID: <87bk0gr50v.fsf@nosuchdomain.example.com> References: <86o74h88ak.fsf@linuxsc.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Sun, 22 Sep 2024 00:55:13 +0200 (CEST) Injection-Info: dont-email.me; posting-host="53afef797043d7014e444c472e5c9c8a"; logging-data="1863283"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18BC3aMTkyL6fWrnRogPfhu" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:AUqTYtnuCQRLiFLrjP+oezrRBaU= sha1:I1BuSsZ4aMCr4bbvYnnINTGQQkM= Xref: csiph.com comp.lang.c:388477 Tim Rentsch writes: > Mark Summerfield writes: >> I have this macro: >> >> #define WARN(...) \ >> do { \ >> fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \ >> fprintf(stderr, __VA_ARGS__); \ >> } while (0); >> >> which I use like this: >> >> total++; >> if (failed) { >> WARN("failed because..."); >> } else >> ok++; >> >> I would prefer to be able to write this instead: >> >> total++; >> if (failed) >> WARN("failed because..."); >> else >> ok++; >> >> but doing so results in a compiler error: >> >> error: 'else' without a previous 'if' > > You can define WARN() this way > > #define WARN(...) ( \ > fprintf(stderr, "%s#%d: ", __FILE__, __LINE__), \ > fprintf(stderr, __VA_ARGS__) \ > ) > > and it will work as you want it to. Good point. To expand on that, the do/while trick (without the trailing semicolon) is the usual way to write a macro that can be used anywhere a statement can appear. But it's not necessary if all you want is a sequence of expression statements. In that case, you can write the expression statements (terminated by semicolons) as expressions (separated by comma operators and enclosed in parentheses), and the whole expansion is a single expression that can be used in an expression statement. The macro can then be used in more contexts, since its expansion is an expression (though that's not likely to matter in this case). An if/else can be turned into a conditional operator, which also gives you an expression, but there's no expression equivalent for most control flow constructs (loops, return, etc.). That's where the do/while trick becomes necessary. For this example (two fprintf calls), you can use either do/while or a comma operator. You might consider using the do/while in case you might want to add control flow later. If you have several similar macros, there's something to be said for being consistent. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */