▸ Object-like macro pitfalls: #define BUFFER_SIZE 256 - safe; #define DOUBLE(x) x*2 - unsafe (DOUBLE(a+b) = a+b*2); correct: #define DOUBLE(x) ((x)*2); double-evaluation: #define MAX(a,b) ((a)>(b)?(a):(b)) evaluates a and b twice - dangerous with side effects (MAX(i++, j++)); C99 inline functions are the safe alternative: static inline uint32_t Max(uint32_t a, uint32_t b) {return a>b?a:b;} - type-safe, single evaluation, optimizer produces equivalent code; MISRA-C:2012 Directive 4.9: function-like macros should be replaced with inline functions where possible
▸ Conditional compilation for hardware variants: #ifdef CPU_TC397B → TC397-specific register definitions; #if (MCU_CLOCK_FREQ == 300000000) → 300MHz-specific clock divider; #ifndef UNIT_TEST → exclude hardware register access in host simulation; AUTOSAR Compiler.h: INLINE, LOCAL_INLINE, FUNC(rettype, memclass), P2CONST(ptrtype, ptrclass, memclass) macros abstract compiler-specific attributes for portability across GCC, Green Hills, Tasking, IAR; Platform_Types.h: CPU_TYPE_8/16/32, CPU_BIT_ORDER, CPU_BYTE_ORDER - auto-selected per target; #error directive: #if !defined(MCU_TYPE) #error "MCU_TYPE must be defined" #endif - enforces required build definitions
▸ X-macro pattern for DID/DTC tables: #define DID_TABLE X(0xF190, "VIN", 17, DID_READ_ONLY) X(0xF18A, "HW_NR", 10, DID_READ_WRITE) X(0xF101, "VARIANT", 1, DID_READ_WRITE); generate enum: enum DID_IDs { #define X(id, name, len, rw) DID_##name, DID_TABLE #undef X }; generate string table: const char *DID_Names[] = { #define X(id, name, len, rw) #name, DID_TABLE #undef X }; eliminates manual synchronization of parallel arrays; used in AUTOSAR generated code (DcmDspDid tables) and DEM event ID enumerations
▸ Token pasting and stringification: ## operator: #define REG(n) REG_##n → REG(STATUS) = REG_STATUS; # operator: #define STRINGIFY(x) #x → STRINGIFY(BUFFER_SIZE) = "256"; used in AUTOSAR DET module: DET_REPORTERROR(MODULE_ID, INSTANCE_ID, API_ID, ERROR_ID) macro compiles to Det_ReportError() call with literal constants; static_assert (C11) in embedded headers: _Static_assert(sizeof(uint32_t)==4, "uint32_t size mismatch") - catches cross-compiler type size differences at compile time; __LINE__ and __FILE__ macros in DET and error logging macros; __func__ (C99) for current function name in assert messages