Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use function-like macros in C

I was reading some code written in C this evening, and at the top of the file was the function-like macro HASH:

#define HASH(fp) (((unsigned long)fp)%NHASH)

This left me wondering, why would somebody choose to implement a function this way using a function-like macro instead of implementing it as a regular vanilla C function? What are the advantages and disadvantages of each implementation?

Thanks a bunch!

like image 731
Ralph Avatar asked Oct 24 '09 03:10

Ralph


People also ask

Is it better to use a macro or a function in C?

Macros are typically faster than functions as they don't involve actual function call overhead.

When would you use a macro function?

Macros are generally used to define constant values that are being used repeatedly in program. Macros can even accept arguments and such macros are known as function-like macros. It can be useful if tokens are concatenated into code to simplify some complex declarations.

What are function-like macros in C?

Function-like macro definition: An identifier followed by a parameter list in parentheses and the replacement tokens. The parameters are imbedded in the replacement code. White space cannot separate the identifier (which is the name of the macro) and the left parenthesis of the parameter list.

What are the advantages of macro over function in C?

When writing macros for functions, they saves a lot of time that is spent by the compiler for invoking / calling the functions. Hence, The advantage of a macro over an actual function, is speed. No time is taken up in passing control to a new function, because control never leaves the home function.


2 Answers

Macros like that avoid the overhead of a function call.

It might not seem like much. But in your example, the macro turns into 1-2 machine language instructions, depending on your CPU:

  • Get the value of fp out of memory and put it in a register
  • Take the value in the register, do a modulus (%) calculation by a fixed value, and leave that in the same register

whereas the function equivalent would be a lot more machine language instructions, generally something like

  • Stick the value of fp on the stack
  • Call the function, which also puts the next (return) address on the stack
  • Maybe build a stack frame inside the function, depending on the CPU architecture and ABI convention
  • Get the value of fp off the stack and put it in a register
  • Take the value in the register, do a modulus (%) calculation by a fixed value, and leave that in the same register
  • Maybe take the value from the register and put it back on the stack, depending on CPU and ABI
  • If a stack frame was built, unwind it
  • Pop the return address off the stack and resume executing instructions there

A lot more code, eh? If you're doing something like rendering every one of the tens of thousands of pixels in a window in a GUI, things run an awful lot faster if you use the macro.

Personally, I prefer using C++ inline as being more readable and less error-prone, but inlines are also really more of a hint to the compiler which it doesn't have to take. Preprocessor macros are a sledge hammer the compiler can't argue with.

like image 64
Bob Murphy Avatar answered Oct 10 '22 06:10

Bob Murphy


One important advantage of macro-based implementation is that it is not tied to any concrete parameter type. A function-like macro in C acts, in many respects, as a template function in C++ (templates in C++ were born as "more civilized" macros, BTW). In this particular case the argument of the macro has no concrete type. It might be absolutely anything that is convertible to type unsigned long. For example, if the user so pleases (and if they are willing to accept the implementation-defined consequences), they can pass pointer types to this macro.

Anyway, I have to admit that this macro is not the best example of type-independent flexibility of macros, but in general that flexibility comes handy quite often. Again, when certain functionality is implemented by a function, it is restricted to specific parameter types. In many cases in order to apply similar operation to different types it is necessary to provide several functions with different types of parameters (and different names, since this is C), while the same can be done by just one function-like macro. For example, macro

#define ABS(x) ((x) >= 0 ? (x) : -(x))

works with all arithmetic types, while function-based implementation has to provide quite a few of them (I'm implying the standard abs, labs, llabs and fabs). (And yes, I'm aware of the traditionally mentioned dangers of such macro.)

Macros are not perfect, but the popular maxim about "function-like macros being no longer necessary because of inline functions" is just plain nonsense. In order to fully replace function-like macros C is going to need function templates (as in C++) or at least function overloading (as in C++ again). Without that function-like macros are and will remain extremely useful mainstream tool in C.

like image 30
AnT Avatar answered Oct 10 '22 06:10

AnT