Robert said:
When writing C99 code is a reasonable recommendation to use inline
functions instead of macros?
For the purposes of portability or long term viability/maintainability,
use of C99 is *not* a reasonable recommendation. You should use C
compilers that will have long term support, or otherwise write code to
the lowest common denominator (portable C/C++.)
Keep in mind that "static" function declarations are usually basically
equivalent to what is intended by C99's "inline". For serious
compilers, there should be no effective difference between the two
(inline further asserts that taking the address of the function is
illegal, however, a static function whose address *isn't* taken (which
it can always determine because it *is* static) becomes equivalent in
functional status.)
What sort of things is it still reasonable to do using macros? For
example, is it reasonable to write type generic functions macros?
#define CUBE(I) ( (I) * (I) * (I) )
Is there some more concise set of things where inline functions should
be used instead of macros?
The general rule of thumb that I use is that complicated macros should
be module local and commented (or obvious). Otherwise, macros should
be limited to constants, or convenience wrappers.
Multi-statement macros, for example?
There's the whole issue of if() else and multi-line macros. The way
you can get around it is to wrap your multi-line macro with a do { ...
} while(0);. Unfortunately many compilers complain that the while (0)
condition is constant and issue a warning. I don't like turning this
warning off in the compiler, because its reasonable if the "0" comes
from some compiler simplifications. So we're kind of in a no-win
scenario here.
Sometimes some kinds of multi-statement macros can lead to interesting
conundrons. Suppose we have the following macro:
#define hf_idxFirst(t,i) {\
i = hf_NOT_FOUND;\
if (NULL != (t)) hf_idxNext(t,i);\
}
This is fine, except that you cannot write code such as this:
for (hf_idxFirst (table, i); !hf_idxIsEnd(table,i);
hf_idxNext(table,i)) {
/* ... */
}
This isn't so much a multi-statement macro issue as much as a control
code fragment limitation issue that gets hidden by a macro.