不同版本GCC下packed结构体成员取非const引用报错问题咨询
问题解答
为什么不同GCC版本编译结果不一致
packed结构体的__attribute__((packed))属性会取消结构体成员的默认内存对齐,所有成员紧凑排布,这就导致结构体里的int a可能没有对齐到CPU要求的4字节地址边界。
C++标准明确要求:非常量左值引用必须绑定到地址对齐的同类型合法左值。如果允许未对齐的成员绑定到非常量引用,会产生两类问题:
- 部分CPU架构(如ARM、MIPS)不支持内存非对齐访问,直接访问会触发硬件异常崩溃;
- 即使x86架构支持非对齐访问,也会带来明显的性能损耗,部分SIMD指令也会因为地址不对齐执行失败。
GCC 4.4及更早版本没有实现对这个规则的严格检查,允许非法绑定,属于编译器的检查漏洞,编译通过的代码实际上存在可移植性风险,属于未定义行为。后续GCC版本(4.7之后逐步完善)修复了这个检查逻辑,严格执行C++标准要求,所以4.8.5版本会直接抛出编译错误,这是合规的正常优化。
为什么加const修饰后可以正常编译
常量左值引用的绑定规则和非常量有本质区别:当绑定的对象地址不对齐、或者类型不严格匹配时,编译器可以隐式生成一个临时的同类型变量,把原对象的值拷贝到对齐的临时变量中,再将const引用绑定到这个临时变量上。
由于const引用本身约定了不会修改指向的对象,这个隐式拷贝行为不会破坏代码逻辑,不会出现修改不生效的问题。你示例中修改后的代码全程没有修改引用指向的值,所以编译器的隐式拷贝是完全安全的,因此可以正常编译通过。
注意:如果强行通过
const_cast去掉const属性修改这个引用,实际修改的是临时变量的值,不会同步到原结构体的成员,属于未定义行为。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

