Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and why use a #define macro(x) instead of function?

Tags:

c++

c

macros

Seeing this question made me wonder why the approach (toy example):

#define foo(x) bar[x] = 0

would ever be preferred over the function:

void foo(unsigned x){ bar[x] = 0; }

Before the question linked above, I've only seen this once before, in the PolarSSL library, where I assumed it to be some sort of optimisation, and tried not to think too much about it.

I assume that using the preprocessor macro replaces the 'call' to be the '(not-) function body' everywhere it exists; whereas the void function may or may not be optimised out by the compiler, and therefore may result in a lot of branching for a small and simple operation or two.

Is there any other benefit?

When is the macro method preferred, and when is it better to trust the compiler?

like image 307
OJFord Avatar asked Dec 21 '14 19:12

OJFord


3 Answers

Firstly, I'd hope your macro was actually:

#define foo(x) do { bar[x] = 0; } while (0)

for proper semicolon swallowing.

One thing in favour of macros is because you think your compiler's optimiser is not good enough. You're probably wrong. But if you've actually looked at the output carefully and know what you are doing, you might be right, which is why it's often used in the Linux kernel.

Another reason is that macros are typeless, so you might do:

#define foo(x,t) do { t[x] = 0; } while (0)

which will work for any type t. Lack of type checking is often a disadvantage, but it can be useful when defining something you want to work with any type.

like image 143
abligh Avatar answered Oct 27 '22 20:10

abligh


Defining macro just to make the code faster is useless. A good compiler will inline function call. However, macros can be useful when you need to use their result as constant.

#define ENCODED(a,b,c,d) (((((((a)<<8)+b)<<8)+c)<<8)+d)

switch (a) {
   case ENCODED('f','o','o','0'):   ...
   case ENCODED('b', 'a', 'r', '1'): ...
}

When you want to define new identifiers:

#define LIB_VERSION v101
#define VERSIONNED(x) x##LIB_VERSION

void VERSIONNED(myfunction)(int x) { ... }

When you want to do some other "magics",. For example:

#define assert(x) {if ((x) == 0) {printf("%s:%d: Assertion %s failed\n", __FILE__, __LINE__, #x); exit(-1); }}

When you want to define a "generic" function working with several types. Just for illustration:

#define DELETE_LAST_ITEM(x) {while (x->next->next != NULL) x=x->next ; x->next = NULL}

and probably some other situations which I do not remember right now.

like image 30
Marian Avatar answered Oct 27 '22 20:10

Marian


Is there any other benefit?

There are few situational benefits of using macro. Just for an example, you may use __LINE__ and __FILE__ to see where this macro is getting called for debugging.

#define foo(x) bar[x] = 0; PrintFunction("...", __FILE__,__LINE__)

The macro would never give you stronger type checking like function.

When is the macro method preferred, and when is it better to trust the compiler?

Hence, Macro should be preferred only when you don't have any choice left to use a function, because most of the times you may trust the compiler optimizer.

like image 4
iammilind Avatar answered Oct 27 '22 20:10

iammilind