Path: ...!2.eu.feeder.erje.net!3.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: how to make a macro work as a single line if stmt without braces Date: Tue, 24 Sep 2024 06:18:08 -0700 Organization: A noiseless patient Spider Lines: 74 Message-ID: <86msjx6vhr.fsf@linuxsc.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Tue, 24 Sep 2024 15:18:10 +0200 (CEST) Injection-Info: dont-email.me; posting-host="601554cda56817d39319d039c1b5e785"; logging-data="3387589"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18ahdx+wLPdSnnFoOXDRoyya6bD9oaBTko=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:eT+q/3rFlSJ7T1u4jR5yqQpQM8I= sha1:XDep7Zxwq62PPh+suN/kihEljhk= Bytes: 3550 Blue-Maned_Hawk writes: > Mark Summerfield wrote: > >> 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' > > Since the initial problem has already been solved by other messages, > here's some extra completely unsolicited advice that you are free to > ignore: > > If you intend for this macro to be invoked like how one would > invoke the printf function (i.e. the arguments consisting of a > format string literal followed by arguments to be formatted into > it), you could get away with defining it like this instead: > > #define WARN(msg, ...) (fprintf(stderr, "%s#%d: " msg, __FILE__, __LINE__ > __VA_OPT__(,) __VA_ARGS__)) > > This would break if you try to invoke it with a nonliteral string, > because this takes advantage of preprocessor adjacent string > literal concatenation, but modern compilers tend to complain > mightily if you try that anyway. It would have the advantage of > expanding to an expression instead, which is often more beneficial > for macros because it permits more flexibility in placement > (something that i find unlikely to be relevant for this particular > one, but which can't really particularly hurt to have anyway). The alternative below works without needing __VA_OPT__, in earlier C standards including C90. #include #include #define WARN(...) (warning_with_origin( __FILE__, __LINE__, __VA_ARGS__ )) int warning_with_origin( const char *file, long line, const char *format, ... ){ va_list ap; int a = (va_start( ap, format ), 0); int b = a < 0 ? a : fprintf( stderr, "%s#%ld: ", file, line ); int c = b < 0 ? b : vfprintf( stderr, format, ap ); int d = c < 0 ? c : fprintf( stderr, "\n" ); return va_end( ap ), d < 0 ? d : a + b + c + d; }