memcmp()行为异常及结构体const修饰影响的原因求助
问题分析与解释
核心问题根源:const修饰的typedef触发未定义行为
你遇到的问题本质是错误地将typedef定义为const限定类型,进而引发了未定义行为,具体拆解如下:
typedef的冗余const导致类型异常
你的typedef写法:typedef const struct drivers { char name[DRIVERS_NAME_BUFF_SIZE]; char version[DRIVERS_VERSION_BUFF_SIZE]; } const drivers;这里第二个
const完全冗余且不符合C语法规范——typedef的作用是给类型起别名,const是修饰类型而非别名的。实际编译器会将其解析为typedef const struct drivers drivers;,即drivers等价于const struct drivers,意味着所有drivers类型的变量都是不可修改的const对象。修改const对象触发未定义行为
代码中after是const drivers类型,你却调用strcpy(after.name, "my-lib")试图修改它的成员数组——这直接违反了C标准中"不得修改const限定对象"的规定,属于未定义行为。
编译器对const对象会做特殊优化(比如将其放入只读内存段、或假设其值永远不会改变),这会导致after的实际内存状态和你预期的不一致:比如编译器可能直接忽略strcpy的写入操作,或者写入后内存状态被破坏。memcmp结果差异的原因
- res1/res2失败:当直接传递
const drivers*类型的指针给memcmp时,编译器会识别到这是指向只读对象的指针,可能基于"const对象不会被修改"的假设进行优化,导致memcmp的比较结果不符合实际内存(比如直接返回非0)。 - res3成功:
uint8_t * base_before = &before;是一个隐式的const指针转非const指针操作(这也是C标准不推荐的),这个转换会绕过编译器对const对象的部分优化,使得memcmp能直接比较实际的内存字节,因此得到了符合预期的结果。
- res1/res2失败:当直接传递
移除const后正常的原因
当去掉typedef中的const修饰后,drivers是普通的结构体类型,after变为可修改对象,strcpy的写入操作合法。此时:before用字符串初始化时,数组中未被字符串覆盖的部分会被值初始化为0;after通过{0}初始化,所有数组元素默认是0,strcpy仅覆盖前几个字节,剩余部分保持0;
两者的内存完全一致,因此所有memcmp都返回0。
修复方案
- 修正typedef的写法,去掉冗余的const:
typedef struct drivers { char name[DRIVERS_NAME_BUFF_SIZE]; char version[DRIVERS_VERSION_BUFF_SIZE]; } drivers; - 如果需要定义不可修改的结构体变量,在变量声明时添加const,而不是在typedef中:
const drivers before = {.name = "my-lib", .version = "1.2.3.4.5"}; drivers after = {0}; // 可修改的变量
内容的提问来源于stack exchange,提问作者HHHH
相关产品推荐
相关产品推荐

