Avoid magic. Do not use macros.Disagree. Use magic, especially macros, in ways such that your code becomes easier, not harder, to understand.
A few examples from my own code:
1. My "elastic arrays" (https://github.com/Tarsnap/libcperciva/blob/master/datastruc... and .c) allow me to write
ELASTICARRAY_DECL(STRLIST, strlist, const char *);
and get a data structure STRLIST which contains an arbitrary number of strings and functions strlist_init, strlist_append, strlist_get, strlist_free, etc. for accessing the array. Compared to the non-macro approach of keeping track of the array size and resizing as needed, this makes code vastly simpler. (Of course, this sort of data structure is built into most non-C languages already.)
2. My "magic getopt" (https://github.com/Tarsnap/libcperciva/commit/53d00e5bd0478f...) allows me to something which looks and behaves just like a standard UNIX getopt loop, except with support for --long options. Yes, the implementation is mildly insane (and needs to work around a bug in clang!), but it allows for code which is vastly simpler than other getopt-with-long-options alternatives.
3. My "cpu features support" framework (https://github.com/Tarsnap/libcperciva/blob/master/cpusuppor...) makes use of both macros and some tricky edge cases of C object linkage rules, but makes it trivial for me to add support for new CPU features.
4. Soon to be released, the PARSENUM macro (WIP: https://github.com/Tarsnap/libcperciva/blob/parsenum-additio...) which allows me to write
PARSENUM(&n, "1234");
PARSENUM(&x, "123.456");
PARSENUM(&s, "123", 0, 1000);
where the first argument is a pointer to a variable of any integer or floating-point type to which is assigned the numeric value of the string in the second argument; for floating-point values and unsigned integers, the two-argument form range-checks the value against the bounds of the type, while the four-argument form range-checks against the provided bounds. (Basically, this is strtonum on steroids.)
In all of these cases, you will never need to understand how these macros work. Instead, you can simply treat them as language extensions which allow you to write cleaner and simpler code.