Sunday, July 15, 2007

Preprocessing Notes

* Scope of Macros
- Until #undef
- Or it is global static in current module
- Or it is global when included

* No Semicolon After Preprocessors

* Be cautious of the space in Macros
This example might not work as you expect:
#define max_(a, b) ((a) > (b) ? (a) : (b)) /* _ represents one space here */

* Arithmetic Calculation Is Allowed in Macro
#define SEC_PER_YEAR (60*60*24*365)UL

* Macros Are Not Functions
- Parenthese usage (the whole Macro and its oprands)
- Avoid evaluating operands more than once, like no such operators in operands, ++, --, etc.

* Macros Are Not Type Definitions
When declaring a new name for pointers, it is better off to use typedef instead of macros.

It is ok to
#define FOOTYPE struct foo
FOOTYPE a, b;

But this is not
#define FOOTYPE struct foo *
FOOTYPE a, b;

Meanwhile, this is allowed for macro but not for typedef:
#define FOOTYPE int
typedef int DOOTYPE;
unsigned FOOTYPE a;
unsigned DOOTYPE d; /* error */

* How to Define a Macro as An Expression?
It is desirous that macros could be used as a single statement and put a semicolon after them. A general solution for this is to use this structure:
do {\
    ...;\
    ...;\ /* No `break;' inside */
    ...;\
} while(0)    /* No semicolon here */
Note: the new line is supposed to begin right after symbol \

A special case for this is if-else. The ?: and || could be used for simplicity due to its specific evaluation order of operands, like the definition of assert macro:
#define assert(exp) ((exp) || _assert_())
Here _assert_() is used to report errors.

* String in Macros
- #define str(s) (b = #s) =>
    str(Hello); == b = "Hello";

* Function Parameters in Macro
- #define Print(x) (printf x) =>
    print(("hello")); == printf("hello");

* ##
For example,
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)
#define BIT_MASK(__bf) (((1U << (bw ## __bf)) - 1) << (bs ## __bf))
#define SET_BITS(__dst, __bf, __val) \
((__dst) = ((__dst) & ~(BIT_MASK(__bf))) | \
(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))

SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);

* Misc
- #if, #elif, #else, #ifdef, #ifndef, #endif, #define, #undef
- #ifdef A; #if defined(A)||!defined(B)
- __LINE__(int), __FILE__(char *), __DATE__(char *), __TIME__(char *)

Reference:
Andrew Koenig, "C Traps and Pitfalls", AT&T Bell Lab

No comments: