Function-like macros are similar to inline
functions, these are useful in some cases, such as temporary debug log:
#ifdef DEBUG
# define LOGFILENAME "/tmp/logfile.log"
# define LOG(str) do { \\
FILE *fp = fopen(LOGFILENAME, "a"); \\
if (fp) { \\
fprintf(fp, "%s:%d %s\\n", __FILE__, __LINE__, \\
/* don't print null pointer */ \\
str ?str :"<null>"); \\
fclose(fp); \\
} \\
else { \\
perror("Opening '" LOGFILENAME "' failed"); \\
} \\
} while (0)
#else
/* Make it a NOOP if DEBUG is not defined. */
# define LOG(LINE) (void)0
#endif
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc > 1)
LOG("There are command line arguments");
else
LOG("No command line arguments");
return 0;
}
Here in both cases (with DEBUG
or not) the call behaves the same way as a function with void
return type. This ensures that the if/else
conditionals are interpreted as expected.
In the DEBUG
case this is implemented through a do { ... } while(0)
construct. In the other case, (void)0
is a statement with no side effect that is just ignored.
An alternative for the latter would be
#define LOG(LINE) do { /* empty */ } while (0)
such that it is in all cases syntactically equivalent to the first.
If you use GCC, you can also implement a function-like macro that returns result using a non-standard GNU extension — statement expressions. For example:
#include <stdio.h>
#define POW(X, Y) \\
({ \\
int i, r = 1; \\
for (i = 0; i < Y; ++i) \\
r *= X; \\
r; \\ // returned value is result of last operation
})
int main(void)
{
int result;
result = POW(2, 3);
printf("Result: %d\\n", result);
}