Barr C编码标准2018示例代码存疑:两处问题是否为错误?
问题1:预处理指令中使用sizeof()的误区
你完全没理解错——标准C中,预处理阶段不能直接使用sizeof()。
预处理是编译流程的早期环节,此时编译器还未解析timer_reg_t这类自定义类型的定义,而sizeof()是编译时运算符,只有当类型被编译器识别后才能计算其大小。直接在#if预处理指令里调用sizeof()违反C标准,必然会触发你遇到的「missing binary operator before token "("」错误。
书中出现这样的示例大概率是笔误,或是针对少数支持非标准扩展的编译器编写的(这类扩展不具备通用性)。正确的做法是用编译时断言替代预处理检查:
- C11及以后版本可直接用
_Static_assert:
_Static_assert(sizeof(timer_reg_t) == 8, "timer_reg_t struct size incorrect (expected 8 bytes)");
- 若要兼容更早的C标准,可利用数组声明的编译报错特性:
typedef char timer_reg_size_check[sizeof(timer_reg_t) == 8 ? 1 : -1];
问题2:缺失右括号的问题
你的判断完全正确——这就是单纯的输入错误。原代码里的#if ((8 != sizeof(timer_reg_t))少了一个闭合的右括号,正确写法应为:
#if (8 != sizeof(timer_reg_t)) // 或者保持双层括号的配对 #if ((8 != sizeof(timer_reg_t)))
额外补充:结构体填充的隐患
结合书中的规则a,你给出的结构体示例还有一个容易忽略的问题:即便手动添加了_unused字段,编译器仍可能因对齐规则插入填充字节。要彻底避免填充,必须使用编译器特定的属性或指令:
- GCC/Clang环境下用
__attribute__((packed)):
typedef struct __attribute__((packed)) { uint16_t count; // offset 0 uint16_t max_count; // offset 2 uint16_t _unused; // offset 4 uint16_t enable : 2; // offset 6 bits 15-14 uint16_t b_interrupt : 1; // offset 6 bit 13 uint16_t _unused1 : 7; // offset 6 bits 12-6 uint16_t b_complete : 1; // offset 6 bit 5 uint16_t _unused2 : 4; // offset 6 bits 4-1 uint16_t b_periodic : 1; // offset 6 bit 0 } timer_reg_t;
- MSVC环境下用
#pragma pack:
#pragma pack(push, 1) typedef struct { // 结构体成员... } timer_reg_t; #pragma pack(pop)
只有这样才能确保结构体大小严格为8字节,匹配外设寄存器的布局要求。
内容的提问来源于stack exchange,提问作者Daniel H Sagarra
相关产品推荐
相关产品推荐

