C Programming – Declaring Functions Using Macros

cmacros

Is it generally encouraged or discouraged to create a pre-processor macro in C, that facilitates the creation of many functions with the same signature (differing only in name). For instance, instead of:

obj *car(const obj *args, obj **envp, GarbageCollector *gc) { ... }
obj *cdr(const obj *args, obj **envp, GarbageCollector *gc) { ... }
obj *cons(const obj *args, obj **envp, GarbageCollector *gc) { ... }
...

you could do:

#define DEF_PRIMITIVE(name) obj *name(const obj *args, obj **envp, GarbageCollector *gc)
DEF_PRIMITIVE(car) { ... }
DEF_PRIMITIVE(cdr) { ... }
DEF_PRIMITIVE(cons) { ... }
...

the point being to reduce tedious repetition in the code. I can see several arguments on either side for whether this is a good idea.

Reasons to do this

  1. Increase in code readibility
  2. Increased ease of changing the signature. i.e. if the signature of all these functions need to be changed, it need only be done in one place. (In my case, I had to change all of the signatures once and it was a real pain)
  3. Potential reduction of errors and time spent when creating new functions of this type.

Reasons not to do this

  1. It obscures the arguments to the functions, making it unclear to someone unfamiliar with the code what the arguments to the function are (if they happen not to see or find the macro definition).
  2. Certain IDEs have trouble with these definitions inhibiting the IDE's ability to refactor or reason about usage of the function.
  3. Extensive use of macros is generally discouraged in C programs, and errors in them generally lead to hard to identify bugs.

Best Answer

The way macros are used makes it very difficult for a programmer to reason about them, and guess what would be the result of a macro. For anything but the most basic examples, macros would usually lead to edge cases and problems which would be very difficult to debug.

Historically, macros were useful for optimization purposes: one call less to a function meant a few CPU cycles saved, which would be a big deal.

Today, you'll hardly find yourself in a case where function calls will be the bottleneck in your code. Especially since “an inline function is as fast as a macro.”

So, no, for the sake of readability, maintenance and reduced headaches, you're not supposed to use macros instead of functions. Functions give you the benefit of type checking, and—if you adjust your code and your compiler options accordingly—the same performance as the macros.