5

I am trying to define a macro that has two line/statements, it's like:

#define FLUSH_PRINTF(x) printf(x);fflush(stdout);

but it can't work due to the limit that C macros cannot work with ';'.

Is there any reasonable way to work around it?

P.S.: I know the upper example is weird and I should use something like a normal function. but it's just a simple example that I want to question about how to define a multiple statement Macro.

pambda
  • 2,640
  • 2
  • 19
  • 31
  • 3
    `but it can't works due to the limit that C Macro can not work with ';'.` What do you mean? Why not write a function? – tkausl May 17 '18 at 14:19
  • Please post a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – MikeCAT May 17 '18 at 14:19
  • If you do want to do that: `#define FLUSH_PRINTF(x) {printf(x); fflush(stdout);}` – Jose May 17 '18 at 14:21
  • Shouldn't fflush be avoided? – Kami Kaze May 17 '18 at 14:24
  • 1
    @KamiKaze: `fflush` is fine for output streams - it's UB for input streams in general (although supported on some platforms). – Paul R May 17 '18 at 14:27
  • @tkausl I know the upper example is weird and I should use something like a normal function. but it's just a simple example that I want to question about how to define a multiple statement Macro. – pambda May 17 '18 at 14:43

3 Answers3

9

This is an appropriate time to use the do { ... } while (0) idiom. This is also an appropriate time to use variadic macro arguments.

#define FLUSH_PRINTF(...) \
    do { \
        printf(__VA_ARGS__); \
        fflush(stdout); \
    } while (0)

You could also do this with a wrapper function, but it would be more typing, because of the extra boilerplate involved with using vprintf.

 #include <stdarg.h>
 #include <stdio.h>

 /* optional: */ static inline 
 void
 flush_printf(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
     vprintf(fmt, ap);
     va_end(ap);
     fflush(stdout);
 }
zwol
  • 129,170
  • 35
  • 235
  • 347
  • 1
    Why an inline function? A normal function would work just as well. – Jabberwocky May 17 '18 at 14:34
  • @MichaelWalz I know the upper example is weird and I should use something like a normal function. but it's just a simple example that I want to question about how to define a multiple statement Macro. – pambda May 17 '18 at 14:44
  • @MichaelWalz I suppose it doesn't need to be inline, no. – zwol May 17 '18 at 14:45
1

Use the multiple expression in macro

#define FLUSH_PRINTF(x) (printf(x), fflush(stdout))

Abhinav
  • 11
  • 2
-2

The best solution is to write a function instead. I don't understand why you need a macro in the first place.

As for how to do it with a macro, simply wrap it in {}:

#define FLUSH_PRINTF(x) { printf(x);fflush(stdout); }

This is perfectly fine as per C11 6.8, resulting in a compound-statement:

statement:
  labeled-statement
  compound-statement
  expression-statement
  selection-statement

If you wish to allow dangerous style if statements with no braces (bad idea), such as:

if(x)
  FLUSH_PRINTF(x);
else
  FLUSH_PRINTF(y);

then you must use the do while(0) trick to wrap the macro:

#define FLUSH_PRINTF(x) do { printf(x);fflush(stdout); } while(0)
Lundin
  • 174,148
  • 38
  • 234
  • 367
  • 1
    You must use `do { ... } while (0)` for this _even if_ your local style guide absolutely forbids the use of what you call "dangerous style if statements". It's not just about that. – zwol May 17 '18 at 14:33
  • I am not the downvoter, but it can't works for multiple args. for example, FLUSH_PRINTF("hello %s\n", "Lundin"); – pambda May 17 '18 at 14:34
  • 1
    (To be more concrete, the most important reason why you need the `do { } while (0)` is that `{ } ;` is a syntax error.) – zwol May 17 '18 at 14:36
  • @zwol No, avoiding do-while(0) means you get a compiler error for dangerous code. This is for example the reason why the recommendation to use do-while(0) in MISRA-C:2004 was removed in MISRA-C:2012. – Lundin May 17 '18 at 14:36
  • Your devotion to MISRA-C, no matter how fanatical, will not get you around the fact that people will want to write `FLUSH_PRINTF("blarg");` as a plain statement - not part of a conditional construct at all - and that's a syntax error if the expansion has the curly braces but not the do-while. – zwol May 17 '18 at 14:38
  • @YanTing_ThePanda Neither does the OP's code. That was not a requirement and variadic macros don't exists in all versions of C. – Lundin May 17 '18 at 14:38
  • @zwol It is perfectly fine to include `{ }` statements anywhere in your code. Are you using Visual Studio or something? – Lundin May 17 '18 at 14:39
  • Updated answer with a reference to the C standard explaining why the code is perfectly fine. – Lundin May 17 '18 at 14:41
  • ... Hmm, you may be right, according to the official grammar `void foo() { { } ; }` should be parsed as an empty block followed by an empty statement, which is fine, but I have definitely used compilers that would throw a hard syntax error on that. If you're objecting to `__VA_ARGS__` on the grounds that not all compilers support it, I get to object to `{ } ;` on the same grounds. – zwol May 17 '18 at 14:42
  • @MichaelWalz That's why the version in my answer uses `...` and `__VA_ARGS__`; it doesn't have anything to do with what me and Lundin are debating. – zwol May 17 '18 at 14:44
  • @zwol Yeah I remember getting that too from some compilers (Visual Studio?), but that just means they aren't compliant. – Lundin May 17 '18 at 14:46
  • @MichaelWalz Try again with the code from the question. No, that doesn't compile either if used as you do. How to create variadic macros was not the question. – Lundin May 17 '18 at 14:49
  • @Lundin I think the point here is that a variadic macro is needed here or a wrapper function like in zwol's answer. Sooner or later the OP wants to do `FLUSH_PRINTF("foo = %d\n", bar);` instead of `FLUSH_PRINTF("foobar");`... – Jabberwocky May 17 '18 at 14:52
  • @MichaelWalz The main concern about the OP seems to be how to place two functions, any functions, behind a macro. – Lundin May 18 '18 at 06:35