22

While browsing sources of LinCAN driver, I found some macros that baffled me.

#else /*CONFIG_PREEMPT*/
#define can_preempt_disable()      do { } while (0)
#define can_preempt_enable()       do { } while (0)
#endif /*CONFIG_PREEMPT*/

I understand the usefulness of

do { 
  ...;
  if(condition) break;
  ... 
} while (0); 

using break as a kind of throw. I semi-understand wrapping a sequence of functions like

#define FOO() do { foo(); bar(); } while (0)

to avoid caveats with braceless if. I understand sometimes "no-op statements" are required for a #define. But why this particular kind? specifically, empty braces, false condition, do...while? Some syntax caveats I can't quite grasp?

M.M
  • 138,810
  • 21
  • 208
  • 365
SF.
  • 13,549
  • 14
  • 71
  • 107

2 Answers2

23

It is a common syntax for notifying the compiler that macro should be treated as a statement instead of as an expression (statements vs expressions).

In this case compiler will alert you if you try to use can_preempt_disable() as an expression. This means that we forced compile-time check that can_preempt_disable() is used as a statement. Compile-time checks are very often desirable.

Community
  • 1
  • 1
plesiv
  • 6,935
  • 3
  • 26
  • 34
  • 2
    `(void)0` would have achieved the goal of preventing the expression's value being used. – M.M Oct 08 '14 at 11:23
17

The complete passage from the relevant file is:

#if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) ||
    (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) )
#define can_preempt_disable preempt_disable
#define can_preempt_enable preempt_enable
#else /*CONFIG_PREEMPT*/
#define can_preempt_disable() do { } while (0)
#define can_preempt_enable() do { } while (0)
#endif /*CONFIG_PREEMPT*/ 

Thus, the first part is the code you get when you've asked for pre-emption protection, otherwise you get the empty, do-nothing, loops.

I guess they're written like that for the usual reasons, i.e. to ensure that the macro still is a valid statement.

There shouldn't be a terminating semicolon in the definition, since that will be in the code using these, such as this function which begins:

int c_can_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
{
    can_preempt_disable(); 

    ...

So, clearly the macro is used like any other function call, and the semicolon is right there where the macro is invoked. This is very normal.

UPDATE 2: Defining it to a ; leads to double semicolons which is ugly, at least in my opinion. An empty brace pair {} would work I guess, but this do/while construct is even more idiomatic since it's often used in cases like these.

UPDATE 3: As pointed out in a comment, an empty brace pair won't work since then you can't put a semicolon after the call. Aah. Thanks!

unwind
  • 391,730
  • 64
  • 469
  • 606
  • That's not quite what I meant - not semicolon at the end, but instead of the whole construct, `#define can_preempt_disable() ;`. Semicolon is a valid null statement. `can_preempt_disable();` would evaluate to `;;` harmlessly. Alternatively, plain empty block `{ }` if you're concerned about braceless `if...else` – SF. Oct 07 '14 at 11:22
  • 8
    @SE If you did `#define can_preempt_disable() ; ` then `if(foo()) can_preempt_disable(); else bar();` -> `if(foo());; else bar();` which is a syntax error. If you defined it to empty, `#define can_preempt_disable()` , then `while(foo()) can_preempt_disable();` -> `while(foo());` would produce a warning with at least some compilers (e.g. clang), and you'd be able to use can_preempt_disable() in places you shouldn't, e.g `for(;can_preempt_disable();)` – nos Oct 07 '14 at 11:37
  • 2
    "An empty brace pair {} would work I guess" -- No, it wouldn't ... `if (x) can_preempt_disable(); else ...` won't compile. The important feature of `do { } while(0)` is that it isn't terminated. – Jim Balter Oct 07 '14 at 11:47
  • @JimBalter Thanks, I knew it but somehow failed to remember when I wrote that. Edited. – unwind Oct 07 '14 at 11:51
  • 1
    A better idea however, is to embrace a coding style where you always use {} after every control statement. Then you don't need to resort to obscure macro tricks. If you have such a careful coding style, then an empty brace pair will work just fine. Because it will give a compiler error when the programmer is sloppy. – Lundin Oct 07 '14 at 14:00
  • @Lundin: I completely agree.`if()` with statement in the next line without braces was a fire'able offense with my previous employer. And as I started working for my current employer, I inherited code littered with surprises like `if(debug) [newline] // printf("some debug message");`. Unfortunately often we're forced to work on a big project where the "always braces" practice is not known. – SF. Oct 07 '14 at 20:00
  • Macros should not be dependent on coding style to work. Anyway, it's irrelevant to the question or to this answer. – Jim Balter Oct 07 '14 at 20:32