3

I was browsing some code and I came across this macro definition

#define D(x) do { } while (0)

And its used in the code like this,

D(("couldn't identify user %s", user));

I ran the code, and that particular line doesn't do anything. So, why would some one define a macro like that?

In case you're wondering, that macro is defined in the _pam_macros.h header file.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
John Doh
  • 73
  • 4

2 Answers2

8

Most likely D is for debugging, and there's an #ifdef elsewhere that makes it do something more useful if debugging is enabled, like output the message or log it to a file. The do/while loop is to make it require a semi-colon at the end, so the user can call it as D(...); instead of just D(...) (see this post)

Community
  • 1
  • 1
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • The `do ... while(0)` thing makes the `;` be parsed gently and the macro behave (a least a very little bit) like a statement. (was already explained in the liked post) – jdehaan Jul 02 '10 at 15:39
  • 1
    Since the body is empty, wouldn't this have been just as good? `#define D(x)` Then `D(x);` becomes `;` which is a nice single statement. – R.. GitHub STOP HELPING ICE Jul 03 '10 at 14:36
  • 1
    @R Good point, I think replacing with an empty body is safe and more common; probably the writer has just had enough bugs from macro expansions that they're in the habit of wrapping every macro in `do/while(0)` even if it's unnecessary – Michael Mrozek Jul 03 '10 at 21:48
0

It's done so that if you forget to add a ; at the end of the macro, it causes an error on compile, as it would if it were a function.

If you made this (admitted useless) macro:

#define DBG(x,y) printf ("Debug output %d\n", x); printf ("  %d\n", x+y); 

you can call the macro like this:

void someFun ()
{
  DBG(10,0)
  DBG(11,40)
}

And it will compile perfectly fine.

The do {...} while (0) forces you to include the ; at the end, in case the macro is later turned into a function - which often happens. When this change is made, all of sudden you may have thousands of syntax errors to fix. The way I would define it would be:

#define DBG(x,y)                   \
do                                 \
{                                  \
  printf ("Debug output %d\n", x); \
  printf ("  %d\n", x+y);          \
} while (0)

Now you must include a ; at the end of the macro. Remember, macros literally replace code during the preprocessor phase.

Now - also consider what would happen if you did this with both macros:

if (x==y)
  DBG(x,y);

It would always print the sum of x and y, regardless of what the if evaluated to if you used the first macro shown.

You're probably thinking, that this would fix it:

#define DBG(x,y) {printf ("Debug output %d\n", x); printf ("  %d\n", x+y);} 

And it would, but you're right back to being able to forget the ';' again.

Clean code isn't necessarily good code, but great code written like garbage will make you think the code sucks. Develop good habits because 5 months down the road, you might have to pull out some code you thought you were done with, and you're going to hate your past self for screwing you over.

Now in your case, the macro wasn't turned into a function, it was simply removed or never populated.

user6269400
  • 129
  • 1
  • 2