By using #define we can define macros with parameters, as if they were functions (sometimes this kind of macros are named inline functions).
These are not real C functions, these macros are pieces of code that will expand into real code before compile time by replacing the so called "parameters". This is alwo known as "call by name".
This expansion is a double sided weapon, it can improve runtime efficiency (at cost of program size) but if we don't have enough care it can turn into a very hard to trace error. This can bee seen in this simple example of inline function without parameters:
#define inline_sum 3+4
If we use this macro in the code we would assume that x will receive 7.
int x = inline_sum;
But, what happens when we add more elements to the equation:
int x = inline_sum * 5;
For the inexpert eye, x will receive 35, but let's see how the C compiler will expand this particular code:
int x = 3 + 4 * 5;
Oops, x receives 23, not 35. This is a very common error when dealing with macros. We should always take care of adding appropriate parenthesis for our inline functions, see:
#define inline_sum (3+4)
This will assign effectively 35 to x:
int x = (3+4) * 5;
Now let's see an example of a macro with parameters:
#define min(a,b) ((a)<(b)?(a):(b))
Even this fully parenthesized inline functions is not safe, code expansion may result in something totally unexpected, like the following example:
int x = min(a++,b)
That will expand into:
int x = ((a++)<(b)?(a++):(b))
woops (a will post increment twice). In this case we should've take into account operators precedence, but even if that care is taken, we can't ensure what a user of our libraries can pass as parameter to an inline function. So the advice is always to expand in paper the macros to ensure we are getting what we want.