GCC编译C代码报strict-aliasing类型双关指针错误修复失败
这个编译错误的核心是代码违反了C语言的严格别名规则:你将json_object_entry**类型的指针(即&value->u.object.values)强制转换为char**类型后解引用,这两种类型不存在合法的别名允许关系,GCC在默认开启-fstrict-aliasing的优化等级下(-O2及以上)会判定该行为属于未定义行为,加上编译选项开启了-Werror,就会直接中断编译。
你之前把object_mem字段从void*改成int*完全没命中问题点——报错来自等号右侧的类型双关逻辑,和左侧赋值目标的类型没有关系。
额外提一句:ISO C官方标准从来没有发布过C14版本,你提到的迁移目标大概率是笔误,要么是C17标准,要么是C++14标准,这个报错和标准版本迁移没有直接关联,属于严格别名规则的适配问题。
按代码合规性、维护成本从优到劣排序:
方案1:移除冗余类型双关,直接做指针偏移(首推)
从代码上下文逻辑判断,这行代码的意图很明确:拿到value->u.object.values指向的内存块起始地址,向后偏移values_size字节的位置,存入object_mem字段。
原写法完全没必要绕“取指针变量地址→转char**→解引用”的弯——C标准明确允许通过char*类型指针访问任意对象的字节,直接把目标指针转成char*做偏移即可,完全符合标准,没有任何未定义行为,也不会触发严格别名报错。
直接把报错行替换为下面的代码即可:
value->_reserved.object_mem = (char *)value->u.object.values + values_size;
方案2:用memcpy做值拷贝绕过别名检查
如果你确认这段老代码有特殊历史逻辑,不能直接改指针计算方式,可以用memcpy来取出指针值,memcpy是GCC特殊识别处理的函数,不会触发严格别名检查:
char *base_ptr; memcpy(&base_ptr, &value->u.object.values, sizeof(base_ptr)); value->_reserved.object_mem = base_ptr + values_size;
这个方案的缺点是代码相对冗余,没有方案1简洁。
方案3:关闭严格别名优化(仅应急用,不推荐)
如果暂时不想修改业务逻辑,可以在GCC编译参数中添加-fno-strict-aliasing,告诉编译器不要基于严格别名规则做优化假设,就不会抛出这个错误。但这个方案会放弃一部分编译器优化能力,也没有解决代码本身的未定义行为,仅适合临时验证编译通过的场景,不建议长期使用。
你贴出的代码中json_alloc的调用参数也存在可移植性风险:values_size + ((unsigned long) value->u.object.values),这里直接把指针强转成整数做算术运算,是老版本C语言JSON库常见的两阶段分配技巧——第一遍扫描时把长度值临时存在指针字段里,第二遍分配时再取出计算大小,这类写法本身就非常容易触发类型别名、指针截断相关的编译问题,如果后续遇到跨平台编译报错,优先排查这部分逻辑。
内容的提问来源于stack exchange,提问作者Sylvain Racine

