利用宏定义在编译阶段检查结构体大小的方法

本文介绍了一组用于检查结构体大小的C语言宏,包括如何验证结构体大小是否等于、不等于、大于、小于、不大于、不小于特定值以及是否为特定值的整数倍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/crazycoder8848/article/details/8292770


=====================================================



typedef struct
{
    char a[100];
} T_XXX;

typedef struct
{
    char a[99];
} T_QQQ;

 

/* 检测结构体的大小是否等于特定值 */
#define    SIZE_OF_TYPE_EQUAL_TO(type, size) \
static inline char size_of_##type##_equal_to_##size() \
{ \
    char __dummy1[sizeof(type) - size]; \
    char __dummy2[size - sizeof(type)]; \
    return __dummy1[-1] + __dummy2[-1]; \
}

 

/* 检测结构体的大小是否不等于特定值 */
#define    SIZE_OF_TYPE_UNEQUAL_TO(type, size) \
static inline char size_of_##type##_unequal_to_##size() \
{ \
    char __dummy1[0==(10/(sizeof(type)-size))]; \
    return __dummy1[-1]; \
}

 

/* 检测结构体的大小是否不大于特定值 */
#define    SIZE_OF_TYPE_NOT_LARGER_THAN(type, size) \
static inline char size_of_##type##_not_larger_than_##size() \
{ \
    char __dummy1[size - sizeof(type)]; \
    return __dummy1[-1]; \
}

 

/* 检测结构体的大小是否不小于特定值 */
#define    SIZE_OF_TYPE_NOT_SMALLER_THAN(type, size) \
static inline char size_of_##type##_not_smaller_than_##size() \
{ \
    char __dummy1[sizeof(type) - size]; \
    return __dummy1[-1]; \
}

 

/* 检测结构体的大小是否小于特定值 */
#define    SIZE_OF_TYPE_SMALLER_THAN(type, size) \
    SIZE_OF_TYPE_NOT_LARGER_THAN(type, size) \
    SIZE_OF_TYPE_UNEQUAL_TO(type, size)

 

/* 检测结构体的大小是否大于特定值 */
#define    SIZE_OF_TYPE_LARGER_THAN(type, size) \
    SIZE_OF_TYPE_NOT_SMALLER_THAN(type, size) \
    SIZE_OF_TYPE_UNEQUAL_TO(type, size)

 

/* 检测结构体的大小是否小于特定值 版本2 */
#define    SIZE_OF_TYPE_SMALLER_THAN2(type, size) \
static inline char size_of_##type##_smaller_than2_##size() \
{ \
    char __dummy1[size - sizeof(type) - 1]; \
    return __dummy1[-1]; \
}

 

/* 检测结构体的大小是否大于特定值 版本2 */
#define    SIZE_OF_TYPE_LARGER_THAN2(type, size) \
static inline char size_of_##type##_larger_than2_##size() \
{ \
    char __dummy1[sizeof(type) - size - 1]; \
    return __dummy1[-1]; \
}

 

/* 检测结构体的大小是否为特定值的整数倍 */
#define    SIZE_OF_TYPE_IS_MULTIPLE_OF(type, size) \
static inline char size_of_##type##_is_multiple_of_##size() \
{ \
    char __dummy1[0 - (sizeof(type) % size)]; \
    return __dummy1[-1]; \
}

/***
    好了,现在开始,想检查什么,调用相应的宏即可。
    如果结构大小不符合要求,则会编译出错。
    注意,对宏的调用,不要写在任何函数内 :-)
***/
SIZE_OF_TYPE_EQUAL_TO(T_XXX, 100)
SIZE_OF_TYPE_UNEQUAL_TO(T_XXX, 99)
SIZE_OF_TYPE_NOT_LARGER_THAN(T_XXX, 100)
SIZE_OF_TYPE_NOT_SMALLER_THAN(T_QQQ, 98)
SIZE_OF_TYPE_LARGER_THAN(T_QQQ, 96)
SIZE_OF_TYPE_SMALLER_THAN(T_QQQ, 200)

SIZE_OF_TYPE_LARGER_THAN2(T_QQQ, 96)
SIZE_OF_TYPE_SMALLER_THAN2(T_QQQ, 200)
SIZE_OF_TYPE_IS_MULTIPLE_OF(T_QQQ, 9)

 

int main()
{
    return 0;
}



在嵌入式开发中,**结构体宏定义**是一种将硬件寄存器映射为结构体并通过宏快速访问的技术,结合了结构体的可读性和宏的灵活性。以下是详细解析: --- ### **1. 结构体宏定义的核心思想** - **结构体定义**:用结构体描述硬件寄存器的布局(偏移量、位宽)。 - **宏定义**:通过宏将基地址转换为结构体指针,简化寄存器访问。 #### **示例代码** ```c // 1. 定义寄存器结构体 typedef struct { volatile uint32_t CR; // 控制寄存器 volatile uint32_t CFGR; // 配置寄存器 volatile uint32_t CIR; // 中断寄存器 // ...其他寄存器 } RCC_TypeDef; // 2. 定义外设基地址(来自芯片手册) #define RCC_BASE 0x40023800U // 3. 宏定义结构体指针 #define RCC ((RCC_TypeDef *)RCC_BASE) // 4. 使用示例 RCC->CR |= (1 << 0); // 开启HSI时钟(直接操作寄存器位) ``` --- ### **2. 关键技术点** #### **(1) 结构体与硬件布局匹配** - **偏移量严格对齐**:结构体成员的偏移必须与硬件手册一致。 - 例如,STM32的RCC->CFGR偏移量为`0x08`,结构体定义需保证`CFGR`是第二个成员(假设`CR`偏移`0x00`)。 - **避免编译器填充**: - 使用`__attribute__((packed))`(GCC)或`#pragma pack(1)`确保无填充字节(但可能影响性能)。 - STM32标准库通常已处理对齐问题。 #### **(2) 宏定义的灵活性** - **直接访问**:`RCC->CR`比`*(volatile uint32_t *)(RCC_BASE + 0x00)`更直观。 - **位操作简化**:结合位域或宏定义位操作: ```c #define RCC_CR_HSION_Pos 0U #define RCC_CR_HSION_Msk (1UL << RCC_CR_HSION_Pos) RCC->CR |= RCC_CR_HSION_Msk; // 开启HSI时钟 ``` #### **(3) 与位带(Bit-Banding)结合** - 在ARM Cortex-M中,可通过宏将寄存器位映射到位带别名区: ```c #define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x02000000 + ((addr & 0x000FFFFF) << 5) + (bitnum << 2)) #define RCC_CR_HSION_BB BITBAND(&RCC->CR, 0) *RCC_CR_HSION_BB = 1; // 原子性置位HSI时钟 ``` --- ### **3. 实际应用场景** #### **场景1:外设初始化** ```c // 使能GPIOA时钟(通过RCC->AHB1ENR寄存器) RCC->AHB1ENR |= (1 << 0); // AHB1总线第0位对应GPIOA ``` #### **场景2:寄存器配置** ```c // 配置USART的波特率(通过USART->BRR寄存器) USART1->BRR = 0x0683; // 假设计算出的波特率分频值 ``` #### **场景3:结合条件编译** ```c // 根据芯片型号选择不同的寄存器定义 #if defined(STM32F4) #define PWM_BASE TIM2_BASE #elif defined(STM32F1) #define PWM_BASE TIM3_BASE #endif #define PWM ((TIM_TypeDef *)PWM_BASE) ``` --- ### **4. 对比其他访问方式** | 方式 | 示例 | 可读性 | 性能 | 可维护性 | |--------------------|-------------------------------|--------|------|----------| | **直接地址操作** | `*(volatile uint32_t *)0x40023800 = 0x1234;` | 差 | 高 | 差 | | **结构体指针** | `RCC->CR = 0x1;` | 优 | 高 | 优 | | **库函数** | `HAL_RCC_HSI_Enable();` | 优 | 中 | 优 | | **位带操作** | `*RCC_CR_HSION_BB = 1;` | 优 | 最高 | 中 | - **选择建议**: - 裸机编程:结构体宏定义(平衡可读性与性能)。 - 复杂项目:厂商库(如STM32 HAL)或RTOS兼容层。 --- ### **5. 常见问题与解决** #### **问题1:结构体成员偏移错误** - **现象**:操作`RCC->CFGR`实际访问了错误的地址。 - **解决**: 1. 对照芯片手册检查偏移量。 2. 使用`offsetof`宏验证: ```c #include <stddef.h> printf("CFGR offset: %d\n", offsetof(RCC_TypeDef, CFGR)); ``` #### **问题2:多任务竞争访问** - **现象**:中断中修改`RCC->CR`导致主循环读取错误值。 - **解决**: - 禁用中断后操作: ```c __disable_irq(); RCC->CR |= (1 << 0); __enable_irq(); ``` - 或使用原子操作(如STM32的`__HAL_LOCK()`)。 #### **问题3:宏重复定义** - **现象**:多个头文件定义了相同的`RCC`宏。 - **解决**: - 使用`#ifndef`保护: ```c #ifndef RCC_MACRO #define RCC_MACRO #define RCC ((RCC_TypeDef *)RCC_BASE) #endif ``` --- ### **6. 高级技巧** #### **(1) 匿名结构体+联合体(位域操作)** ```c typedef struct { union { volatile uint32_t CR; struct { volatile uint32_t HSION : 1; // 位域定义每一位 volatile uint32_t HSIRDY : 1; // ...其他位 } CR_Bits; }; } RCC_TypeDef; // 使用位域访问 RCC->CR_Bits.HSION = 1; // 更直观的位操作 ``` #### **(2) 动态寄存器基地址** ```c // 根据芯片型号动态选择基地址 extern uint32_t g_rcc_base; #define RCC ((RCC_TypeDef *)g_rcc_base) ``` --- ### **总结** - **优势**: - 提高代码可读性(直接使用`RCC->CR`而非地址计算)。 - 便于批量操作寄存器(如结构体赋值初始化)。 - **注意事项**: 1. 严格对齐硬件手册的寄存器布局。 2. 在多任务环境中注意竞态条件。 3. 避免过度使用位域(可能影响编译器优化)。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值