如何不改动原有代码,高效检查经memset初始化的结构体是否被修改
解决方案
因为无法修改原有结构体定义和初始化逻辑,核心判断逻辑基于「对比目标结构体内存和全零模板是否完全一致」,memset会把结构体包括对齐填充位在内的所有内存都置为0,所以直接对比整块内存即可,不需要单独校验每个成员。
方案1:通用标准实现(优先推荐)
兼容性最好,不需要适配平台,性能足够覆盖99%的使用场景:
#include <string.h> // 传入要校验的结构体指针,返回1表示仍为全零初始状态,0表示被修改过 int is_teststruct_unmodified(const teststruct *obj) { // 静态存储期的结构体默认全零初始化,和memset置零结果完全匹配 static const teststruct zero_template; return memcmp(obj, &zero_template, sizeof(teststruct)) == 0; }
说明:
- 静态变量
zero_template只会在程序启动时初始化一次,没有额外运行时开销 - 主流编译器会对memcmp做高度优化,小尺寸结构体的对比会直接展开为寄存器操作,没有函数调用开销,大尺寸结构体也会自动调用向量指令加速。
方案2:手动优化实现(仅适用于超大结构体极端性能需求)
如果结构体尺寸非常大(比如几MB级别),可以手动按机器字长对比进一步压榨性能:
#include <stdint.h> int is_teststruct_unmodified_fast(const teststruct *obj) { size_t remain_size = sizeof(teststruct); // 先按64位字长对比,适配64位平台 const uint64_t *p64 = (const uint64_t *)obj; while (remain_size >= sizeof(uint64_t)) { if (*p64++ != 0) { return 0; } remain_size -= sizeof(uint64_t); } // 剩余不足8字节的部分按字节对比 const uint8_t *p8 = (const uint8_t *)p64; while (remain_size > 0) { if (*p8++ != 0) { return 0; } remain_size--; } return 1; }
说明:该实现依赖结构体首地址满足机器字长对齐要求,C标准要求结构体变量的首地址默认满足最大基本成员的对齐要求,所以正常使用不会出现内存访问异常。
注意事项
- 不要单独对比每个结构体成员,不仅开发成本高,还会漏掉结构体对齐填充位的校验,无法检测到填充位被意外修改的场景
- 两种实现都不需要修改原有历史代码,只需要新增校验函数即可直接调用
内容的提问来源于stack exchange,提问作者Zeta
相关产品推荐
相关产品推荐

