P99
Safety of macro programming and pitfalls

Often we may hear arguments that function like macros obfuscate the code, are dangerous, not maintainable, in short: the big evil.

I am convinced that this is just one of the other urban legends. Macros as such are not less safe than, say, the use of pointers or of a high quality sharpened kitchen knife. And they belong to C as the for or the ++ operator.

Macros can make your code easier readable, better maintainable, more precise and more efficient than you ever would do by writing code "directly" without macros. It is all about how you write them, if you do that yourself, and how you use them.

As one example look at the following code:

 if (P99_ARE_ORDERED(<, a, b, c, d, e, f)) {
   // all are in order, do something special
 } else {
   // handle the base case
 }

In the example a part of the efficiency also comes from the fact that it is not a function. This is e.g interesting if some of the variables in the list are of integer type and the others of floating type: promotions from integer type to floating type will only be performed where necessary in a comparison of two adjacent variables. In such a way we can profit of the exact comparison for integer types and can avoid the problems of rounding an integer to the next representable double. (Think of comparing e = UINT64_MAX - 1 and e = UINT64_MAX.)

But, macros have pitfalls, in particular one important pitfall: you don't see from a macro call if the arguments are evaluated multiple times or not. So if you have the habit to program with side effects, you really have to be careful.

The simplest really is to avoid that, don't have expressions with side effects such as ++ as arguments to macros or functions. Really, don't do that.

If you are programming macros, you have to be more careful since you can't assume that everybody knows what she or he is doing. For P99 we an automatic suite of scripts that tests if any of the macros that start with "P99_" evaluate their arguments multiple times. This is a bit tricky, special care has to be taken for macros that use the ternary operator ?: and the sizeof operator:

The mentioned scripts help us detect these and other special cases and the documentation of the corresponding P99 macros is then annotated with warnings and remarks that document the special behavior of these macros.

See also:
P00_DECLARE_ATOMIC_TYPE(0) for argument 1, 2.
P99_AARG(TYPE, NAME, DIM, VAR) for argument TYPE, DIM.
P99_AASSIGN(TARGET, SOURCE, N) for argument TARGET, SOURCE.
P99_ACALL(ARR, N, TYPE) for arguments ARR, N, TYPE.
P99_ACCESSORS(X, N) for argument X, N.
P99_ACOPY(TYPE, N, ...) for argument __VA_ARG__[0], __VA_ARG__[2].
P99_ALEN(ARR, N) for argument ARR, N.
P99_ALENS(ARR, N) for argument ARR, N.
P99_ARE_EQ(FIRST, ...) for argument FIRST.
P99_ARE_ORDERED(OP, ...) for arguments OP, __VA_ARG__[0], __VA_ARG__[1].
P99_ASORT(TAB, COMP) for argument TAB.
P99_ATOMIC_INHERIT(T) for argument T.
P99_BIGFUNC(FUNC, M, ...) for argument M.
P99_BIGOP(OP, M, ...) for argument M.
P99_CALLOC(T, N) for argument T.
P99_CALL_DEFARG(NAME, M, ...) for argument M.
P99_CALL_DEFARG_LIST(NAME, M, ...) for argument M.
P99_CALL_VA_ARG(NAME, M, T, ...) for argument M.
P99_CASERANGE(START, ...) for argument START, __VA_ARG__[0].
P99_CDIM(NAME, ...) for argument NAME.
P99_CHOOSE5(xT, cc, cs, ci, cl, cll) for argument xT.
P99_DECLARE_ATOMIC(T, NAME) for argument T.
P99_DECLARE_ATOMIC_LOCK_FREE(T, NAME) for argument T, NAME.
P99_DECLARE_DELETE(T) for argument T.
P99_DECLARE_ENUM(T, ...) for arguments T, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_DECLARE_ENUM_GETNAME(T, ...) for arguments T, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_DECLARE_ENUM_PARSE(T, ...) for arguments T, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_DECLARE_INIT_ONCE(T, NAME, ARG) for arguments T, NAME, ARG.
P99_DECLARE_INLINE_EXPRESSION(EXT, BASE, EXP, ...) for arguments EXT, BASE, EXP.
P99_DECLARE_INLINE_EXPRESSIONS(NEPL, ...) for argument NEPL.
P99_DECLARE_STRUCT(NAME) for argument NAME.
P99_DECLARE_UNION(NAME) for argument NAME.
P99_DEC_DOUBLE(...) for arguments __VA_ARG__[1], __VA_ARG__[2], __VA_ARG__[4].
P99_DEFINE_ENUM(T) for argument T.
P99_DEFINE_UNION(NAME, ...) for arguments NAME, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_DERIVED_TYPES(T) for argument T.
P99_DESIGNATED(VAR, ...) for arguments VAR, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_DO(TYPE, VAR, ...) for argument TYPE.
P99_ENC_DECLARE(T, NAME) for argument T, NAME.
P99_FCALLOC(T, F, N) for arguments T, F, N.
P99_FHEAD(T, F, P) for argument T.
P99_FMALLOC(T, F, N) for arguments T, F, N.
P99_FOR(NAME, N, OP, FUNC, ...) for arguments NAME, N, FUNC.
P99_FORALL(NAME, ...) for argument NAME.
P99_FREALLOC(P, T, F, N) for arguments T, F, N.
P99_FSIZEOF(T, F, N) for arguments T, F, N.
P99_GENERIC(...) for argument __VA_ARG__[0], __VA_ARG__[2].
P99_GENERIC_LIT(...) for argument __VA_ARG__[0], __VA_ARG__[2].
P99_GENERIC_SIZE(UI, ...) for arguments UI, __VA_ARG__[1], __VA_ARG__[2].
P99_GENERIC_SIZE_LIT(UI, ...) for arguments UI, __VA_ARG__[1], __VA_ARG__[2].
P99_GEN_ABS(A) for argument A.
P99_GEN_EXPR(BASE, EXPR, ...) for argument BASE, EXPR.
P99_GEN_MAX(A, B) for argument A, B.
P99_GEN_MIN(A, B) for argument A, B.
P99_GEN_SIN(A) for argument A.
P99_GUARDED_BLOCK(T, NAME, INITIAL, BEFORE, AFTER) for arguments T, NAME, AFTER.
P99_HEX_DOUBLE(...) for arguments __VA_ARG__[1], __VA_ARG__[2], __VA_ARG__[4].
P99_HTONL(X) for argument X, 1.
P99_HTONS(X) for argument X, 1.
P99_INVARIANT(EXPR) for argument EXPR.
P99_IPOW(N, X) for argument N, X.
P99_ISSIGNED(T) for argument T.
P99_IS_INF(FIRST, ...) for argument FIRST.
P99_IS_MAX(FIRST, ...) for argument FIRST.
P99_IS_MIN(FIRST, ...) for argument FIRST.
P99_IS_ONE(FIRST, ...) for argument FIRST.
P99_IS_SUP(FIRST, ...) for argument FIRST.
P99_JOIN(...) for arguments __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_LCOPY(TYPE, VAR, ...) for arguments TYPE, VAR, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_LIFO_CLEAR(L) for argument L.
P99_LIFO_POP(L) for argument L.
P99_LIFO_PUSH(L, EL) for argument L, EL.
P99_LIFO_TABULATE(TYPE, TAB, L) for arguments TYPE, TAB, L.
P99_LIFO_TOP(L) for argument L.
P99_LITERAL(...) for arguments __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2], __VA_ARG__[3].
P99_MACRO_PVAR(NAME, ...) for argument NAME, __VA_ARG__[0].
P99_MACRO_VAR(NAME, ...) for argument NAME, __VA_ARG__[0].
P99_MAC_ARGS(...) for arguments __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_MAXOF(0) for argument 1.
P99_MEMSET(TA, SO, N) for argument SO.
P99_MEMZERO(T, TA, N) for argument T.
P99_MINOF(A, B) for argument A, B.
P99_MUTUAL_EXCLUDE(MUT) for argument MUT.
P99_NAME(N, NAME) for argument N.
P99_NTOHL(X) for argument X.
P99_NTOHS(X) for argument X.
P99_PARALLEL_DO(TYPE, VAR, ...) for argument TYPE.
P99_PARALLEL_FORALL(NAME, ...) for argument NAME.
P99_PLAIN_TYPE(T) for argument T.
P99_POINTER_TYPE(T) for argument T.
P99_POSS(N) for argument N.
P99_PRAGMA_DO(PRAG, TYPE, VAR, ...) for argument TYPE.
P99_PRI(xT, F, LEN) for argument xT.
P99_PROTOTYPE(RT, NAME, ...) for argument RT, __VA_ARG__[0].
P99_PZERO(X, N) for argument X.
P99_QSORT(TAB, NB, COMP) for argument TAB.
P99_REP(...) for arguments __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_REPEAT(MACRO, N) for argument MACRO, N.
P99_SEP(MACRO, ...) for argument MACRO.
P99_SEQ(MACRO, ...) for argument MACRO.
P99_SER(MACRO, ...) for argument MACRO.
P99_SIGNED_REPRESENTATION(T) for argument T.
P99_SIZE_CHOICE(UI, YES, NO, ...) for arguments UI, YES, NO.
P99_SIZE_INDICATOR(UI, ...) for argument UI.
P99_STRDUP(...) for arguments __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_STRUCT_LITERAL(TYPE, ...) for arguments TYPE, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_STRUCT_TYPE0(TYPE, ...) for arguments TYPE, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2], __VA_ARG__[3].
P99_STRUCT_TYPES(TYPE, ...) for arguments TYPE, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2], __VA_ARG__[3].
P99_STRUCT_UNUSE(TYPE, VAR, ...) for arguments TYPE, VAR, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_STRUCT_USE(TYPE, VAR, ...) for arguments TYPE, VAR, __VA_ARG__[0], __VA_ARG__[1], __VA_ARG__[2].
P99_SWAP(_0, _1) for argument _0, _1.
P99_TMAX(T) for argument T.
P99_TMIN(T) for argument T.
P99_TOKJOIN(TOK, ...) for argument TOK.
P99_TO_UNSIGNED(T, MACRO) for argument T, MACRO.
P99_TYPE_ARITHMETIC(EXP) for argument EXP.
P99_TYPE_BASIC(EXP) for argument EXP.
P99_TYPE_CHARACTER(EXP) for argument EXP.
P99_TYPE_CHOICE(EXP, YES, NO, ...) for arguments EXP, YES, NO.
P99_TYPE_COMPLEX(EXP) for argument EXP.
P99_TYPE_FLOATING(EXP) for argument EXP.
P99_TYPE_INTEGER(EXP) for argument EXP.
P99_TYPE_REAL(EXP) for argument EXP.
P99_TYPE_REAL_FLOATING(EXP) for argument EXP.
P99_TYPE_SIGNED(EXP) for argument EXP.
P99_TYPE_UNSIGNED(EXP) for argument EXP.
P99_TZERO(X) for argument X.
P99_UINT_DEFAULT(T) for argument T.
P99_UNROLL(MACRO, N) for argument MACRO, N.
P99_UT_MAX(T) for argument T.
P99_VASSIGNS(NAME, ...) for argument NAME.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines