C語言_01_宏定義使用技巧

對於底層軟件開發的工程師, 對宏定義肯定不陌生吧, 我在寫代碼的時候就習慣使用宏定義, 代碼結構清晰, 修改也及其便捷, 在以下場景時使用宏定義的優勢.

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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章