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);
}