tags:

views:

568

answers:

4

According to the C FAQ, there are basically 3 practical methods for "inlining" code in C:

#define MACRO(arg1, arg2) do { \
    /* declarations */ \
    stmt1;   \
    stmt2;   \
    /* ... */  \
    } while(0)    /* (no trailing ; ) */

or

#define FUNC(arg1, arg2) (expr1, expr2, expr3)

To clarify this one, the arguments are used in the expressions, and the comma operator returns the value of the last expression.

or

using the inline declaration which is supported as an extension to gcc and in the c99 standard.

The do { ... } while (0) method is widely used in the Linux kernel, but I haven't encountered the other two methods very often if at all.

I'm referring specifically to multi-statement "functions", not single statement ones like MAX or MIN.

What are the pros and cons of each method, and why would you choose one over the other in various situations?

A: 

The only pro I can see in using any of the constructs is for making it faster code.

So, choose the one method that gives fastest code!

If it's all the same, then I find it more legible

  1. a 'standard' function
  2. a inline function
  3. the #define ... do {} while(0) approach
  4. the macro with comma separated "statements"
pmg
+4  A: 

One pro of using the inline keyword is that you get a check of the types of the arguments via the function prototype. Using macros you get nothing like that, so macros are liable to create strange errors if you put things of the wrong type in them. (Not nearly as horrible as template errors in C++ though.)

One pro of using macros is that you can do funky things like concatenations and turning the macro argument into a string using #arg. Another plus of using preprocessor macros is you can easily check how they expand using cpp to unwind them. This is how you debug those errors.

Another useful point of macro-defined functions is that you can stick a return statement into them to halt the parent function if you need to. With an inline function you have to return a value and then check the return value.

Kinopiko
Actually, I kind of wish function templates were available in C. That way you could get the flexibility of macros with the type safety of functions.
Robert S. Barnes
+5  A: 

Talking abut that specific use of macros, i.e. macros that act as "functions", I'd mention the following advantages of macros that can't be had in inline function:

Lazy argument evaluation. For example, a macro like this

#define SELECT(f, a, b) ((f) ? (a) : (b))

would preserve the lazy argument evaluation properties of the ternary operator: only the selected parameter is evaluated, while the other is not. A straighforward inline-function analogue would evaluate both arguments in advance, thus doing the extra unnecessary work.

Access to context. Macros can be used to implement some resemblance of "local functions", i.e. repetitive pieces of code that have access to the local variable and parameters of the enclosing function.

Type independence (and type parameters). Macros allow you to write type-independent "functions" (see above example). And in case you can't get rid of type-dependency, you can pass types as parameters to the macro.

The above properties of the macros, which I presented as their pros, could be misused to lead to major failures (and thus cold be presented as cons as well). But that's something that can be said of many language features in C.

AndreyT
+1 Those are all good points.
Kinopiko
In an example like #define MAX(A, B) ((A)>(B)?(A):(B)) if A or B includes an action (like i++), it is even worst because it will be evaluated twice.
eyalm
@AndreyT: Perhaps you could spell out some of those cons?
Robert S. Barnes
Robert S. Barnes
A: 

macro function is preprocessor

asma