對於底層軟件開發的工程師, 對宏定義肯定不陌生吧, 我在寫代碼的時候就習慣使用宏定義, 代碼結構清晰, 修改也及其便捷, 在以下場景時使用宏定義的優勢.
1. 防止頭文件被重複包含
#ifndef MAIN_H
#define MAIN_H
..... //代碼部分, 一般爲全局變量, 函數聲明
#endif
2. 簡單函數實現
#define ABS(x) ((x)>=0 ? (x):(-x);) //取絕對值
#define ADD(x,y) ((x)+(y)) //加法
#define MAX(x,y) ((x)>(y) ? (x):(y)) //最大值
3. 獲取變量地址
#define PTR(var) ((UINT32*)(void*)&(var))
4. 字節拼字/字拆字節
#define BYTE_TO_WORD(ray) ((word)((ray)[0]*256)+(ray)[1]) //字節拼字 LSB方式
#define WORD_TO_BYTE(ray,val) \
(ray)[0] = ((val)/256); \
(ray)[1] = ((val) & 0xFF) //字拆字節
5. 類型重定義, 使代碼跨平臺和編譯器
typedef unsigned char UINT8;
typedef signed char INT8;
typedef unsigned short UINT16;
typedef signed short INT16;
typedef unsigned long int UINT32;
typedef signed long int INT32;
typedef UINT8 BOOL;
6. 獲取成員在結構體中的偏移/所佔字節數
#define MEM_OFF(type, field) (((UINT32)&(type *)0)->field) //偏移
#define MEM_SIZE(type, field) (sizeof(type *)0)->field) //所佔字節數
7. 獲取指定地址上的字節/半字/字
#define ADDR_BYTE(x) (*(UNIT8*)(x)) //字節
#define ADDR_BYTE(x) (*(UNIT16*)(x)) //半字
#define ADDR_WORD(x) (*(UINT32*)(x)) //字
8. 大小寫轉換
#define WORD_LOW(c) ((c)>='A' && (c)<='Z') ? ((c)+0x20) : (c))
#define WORD_UP(c) ((c)>='a' && (c)<='z') ? ((c)-0x20) : (c))
9. 檢查是否是十進制/十六進制
#define DEC_CHK(c) ((c)>='0' && (c)<='9') //十進制
#define HEX_CHK(c) ((c)>='0' && (c)<='9') || \
((c)>='A' && (c)<='F') || \
((c)>='a' && (c)<='f') //十六進制
10. 獲取半字的高低位
#define WORD_LO(c) (UINT8) ((UINT16)(c) & 0xFF)) //低8位
#define WORD_HI(c) (UINT8) ((UINT16)((c)>>8) & 0xFF)) //高8位
11. 結構體初始化
typedef struct //結構體定義
{
uint16_t prescaler; /**< Prescaler. */
uint8_t interrupt_priority; /**< Interrupt priority. */
uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */
bool reliable; /**< Reliable mode flag. */
} nrf_drv_rtc_config_t;
#define NRF_DRV_RTC_DEFAULT_CONFIG \ //使用宏初始化結構體成員變量
{ \
.prescaler = RTC_FREQ_TO_PRESCALER(RTC_DEFAULT_CONFIG_FREQUENCY), \
.interrupt_priority = RTC_DEFAULT_CONFIG_IRQ_PRIORITY, \
.reliable = RTC_DEFAULT_CONFIG_RELIABLE, \
.tick_latency = RTC_US_TO_TICKS(NRF_MAXIMUM_LATENCY_US, RTC_DEFAULT_CONFIG_FREQUENCY), \
}
static nrf_drv_rtc_config_t const m_rtc_config = NRF_DRV_RTC_DEFAULT_CONFIG;
12. 防止溢出
#define OVERFLOW(val) (val = ((val)+1 > (val)) ? (val)+1 : (val))
13. 求數組元素個數
#define ARR_NUM(a) ((sizeof(a)/sizeof(a[0]))
14. 求最接近的倍數值 //常用於內存分配
#define POWER8(x) ((((x)+7)/8)*8)
15. 用於跟蹤調試 //ANSI標準(僅限於標準編譯器, 非標準編譯器可能支持不全或不支持)
__LINE__ //對應 %d 表示當前指令所在行, 是個整型數
__FILE__ //對應 %s 表示當前指令所在文件, 包含完整路徑
__DATE__ //對應 %s 包含形式爲月/日/年的字符串, 表示源文件被翻譯到代碼時的日期
__TIME__ //對應 %s 包含源代碼翻譯到目標代碼的時間, 字符串形式爲 時:分:秒
__STDC__ //含有十進制常量1, 如果它含有任何其它數,則實現是非標準的
16. 調試使用
#ifdef __DEBUG
#define DEBUG_MSG(msg, date) printf(msg); printf("%d%d%d", date, __LINE__, __FILE__)
#else
#define DEBUG_MSG(msg, date)
17. 防止多次初始化(只能進行一次)
#define NRF_LOG_INTERNAL_FLUSH() \
do { \
while (NRF_LOG_INTERNAL_PROCESS()); \
} while (0)