1、宏定义技巧

常用关键字重定义

根据不同编译器,定义常用的关键字。

包含:

  • __USED: 告诉编译器,即使一个变量或函数在代码中没有被直接使用,也保留它的定义,避免被编译器优化掉
  • __WEAK: 标识弱函数
  • _ _PACKED: 用于修饰取消字节对其
  • __PACKED_STRUCT: 用于取消结构体的字节对齐
  • __PACKED_UNION: 用于取消公用体的结构对齐
  • __ALIGNED(X): 用于指定对齐方式
  • __ALIGN_BEGIN、__ALIGN_END:__ALIGN_BEGIN 是一个占位符宏,往往与 __ALIGN_END 一起使用,用于在代码中指定对齐的起始位置
  • __UNUSED: 告诉编译器,参数未使用,用于消除警告
#if defined(__CC_ARM)
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __attribute__((packed))
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT __packed struct
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION __packed union
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#elif defined(__GNUC__)
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __attribute__((packed, aligned(1)))
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
#ifndef __USED
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __USED __attribute__((used))
#else
#define __USED __root
#endif
#endif

#ifndef __WEAK
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __WEAK __attribute__((weak))
#else
#define __WEAK _Pragma("__weak")
#endif
#endif

#ifndef __PACKED
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED __packed
#endif
#endif

#ifndef __PACKED_STRUCT
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED_STRUCT __packed struct
#endif
#endif

#ifndef __PACKED_UNION
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED_UNION __packed union
#endif
#endif

#ifndef __ALIGNED
#if defined(__ICCARM_V8) || defined(__ICCRISCV__)
#define __ALIGNED(x) __attribute__((aligned(x)))
#elif (__VER__ >= 7080000)
/* Needs IAR language extensions */
#define __ALIGNED(x) __attribute__((aligned(x)))
#else
#warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored.
#define __ALIGNED(x)
#endif
#endif

#endif

#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif
#ifndef __ALIGN_END
#define __ALIGN_END __attribute__((aligned(4)))
#endif

#ifndef __UNUSED
#define __UNUSED(x) (void)(x)
#endif

取最高最低字节

#ifndef LO_BYTE
#define LO_BYTE(x) ((uint8_t)(x & 0x00FF))
#endif

#ifndef HI_BYTE
#define HI_BYTE(x) ((uint8_t)((x & 0xFF00) >> 8))
#endif

比较大小

#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif

BCD转化

用于将一个十进制数字转换为 BCD(二进制编码十进制)格式。

该宏接受一个参数 x,该参数可以是任何类型的数据。宏定义中的表达式将 x 分解为十进制的十位和个位数字,并将其分别转换为四位二进制编码的十进制数(BCD 码)。然后,它将这两个 BCD 段连接起来,返回一个字节(byte)类型的值。

例如,如果 x 的值为 35,则 BCD(x) 的值将为 0x35。

#ifndef BCD
#define BCD(x) ((((x) / 10) << 4) | ((x) % 10))
#endif

获取数组元素的个数

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) \
    ((int)((sizeof(array) / sizeof((array)[0]))))
#endif

交换字节顺序

BSWAP16 宏,它接受一个参数 u16,该参数必须是一个 16 位无符号整数。宏定义中的表达式使用系统提供的内置函数 __builtin_bswap16(u16),对 u16 参数进行字节交换操作,从而得到交换后的结果。

例如,如果 u16 的值为 0x1234,则 BSWAP16(u16) 的值将为 0x3412。

BSWAP32 宏,它接受一个参数 u32,该参数必须是一个 32 位无符号整数。宏定义中的表达式使用系统提供的内置函数 __builtin_bswap32(u32),对 u32 参数进行字节交换操作,从而得到交换后的结果。

例如,如果 u32 的值为 0x12345678,则 BSWAP32(u32) 的值将为 0x78563412。

#ifndef BSWAP16
#define BSWAP16(u16) (__builtin_bswap16(u16))
#endif
#ifndef BSWAP32
#define BSWAP32(u32) (__builtin_bswap32(u32))
#endif

字节数组提取和封装(大端序)

#define GET_BE16(field) \
    (((uint16_t)(field)[0] << 8) | ((uint16_t)(field)[1]))

#define GET_BE32(field) \
    (((uint32_t)(field)[0] << 24) | ((uint32_t)(field)[1] << 16) | ((uint32_t)(field)[2] << 8) | ((uint32_t)(field)[3] << 0))

#define SET_BE16(field, value)                \
    do {                                      \
        (field)[0] = (uint8_t)((value) >> 8); \
        (field)[1] = (uint8_t)((value) >> 0); \
    } while (0)

#define SET_BE24(field, value)                 \
    do {                                       \
        (field)[0] = (uint8_t)((value) >> 16); \
        (field)[1] = (uint8_t)((value) >> 8);  \
        (field)[2] = (uint8_t)((value) >> 0);  \
    } while (0)

#define SET_BE32(field, value)                 \
    do {                                       \
        (field)[0] = (uint8_t)((value) >> 24); \
        (field)[1] = (uint8_t)((value) >> 16); \
        (field)[2] = (uint8_t)((value) >> 8);  \
        (field)[3] = (uint8_t)((value) >> 0);  \
    } while (0)

数据分割

用于将 16 位无符号整数转换为 2 个字节,并以逗号分隔。

用于将 32 位无符号整数转换为 4 个字节,并以逗号分隔。

#define WBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF)
#define DBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF), ((x >> 16) & 0xFF), ((x >> 24) & 0xFF)

设置获取Bit位

它接受两个参数:var是要设置bit位的变量,pos是要设置的bit位的索引(从0开始)。

#define SET_BIT(var, pos) ((var) |= (1 << (pos)))
#define CLEAR_BIT(var, pos) ((var) &= ~(1 << (pos)))
#define GET_BIT(var, pos) (((var) >> (pos)) & 1)