3

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.
2
  • 2
    Why do you need a bunch of functions with identical signatures to begin with?
    – RubberDuck
    Apr 1, 2018 at 21:05
  • @RubberDuck theyre all primitive procedures a lisp interpreter. They all have the same signature because they all are called in the same way from within the interpreter from just a function pointer. Which one gets called depends on which is specified from the input.
    – Jon Deaton
    Apr 1, 2018 at 21:09

1 Answer 1

4

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.

3
  • 3
    I'm getting the vibe the OP is not trying to avoid function calls, but to use the preprocessor to trivially define new ones, i.e. a half-baked template system. Apr 1, 2018 at 21:25
  • @whatsisname Indeed for my application its not so much about performance but about reducing code repetitiveness.
    – Jon Deaton
    Apr 1, 2018 at 21:58
  • 2
    @whatsisname: Regardless of the purpose, if you can do it with ordinary code, that is almost always preferable to macros or preprocessors, even if the code is a bit more repetitive. The question asks "is it generally encouraged or discouraged," and this is the correct answer to that question. Apr 2, 2018 at 15:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.