You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++标准是否允许对标准布局结构体的同类型成员执行指针运算?

C++20标准下标准布局struct同类型连续成员的指针算术问题结论

你示例中对struct成员指针做算术运算的行为属于未定义行为,C++20标准没有任何条款保证&m.a + 1 == &m.b成立,即使MyStruct是标准布局类型。

规则依据

1. 指针算术的有效范围

C++20 [expr.add] 章节明确限定了指针算术的合法场景:

  • 仅当指针指向某个数组的元素时,对该指针做加减整数的运算才具备明确定义,运算结果不能超出数组边界(含尾后一个位置)。
  • 指向单个非数组对象的指针,视为指向长度为1的数组的第0位元素,仅允许做+1运算得到合法的尾后指针,该尾后指针不可解引用,也不保证指向其他有效对象。

你给出的数组示例是完全合法的,因为所有指针操作都在int m[3]的数组范围内:

// Legit
int m[3] = {0, 1, 2};
int const *p = m;
std::cout << *p << *(p + 1) << *(p + 2) << std::endl;

但对struct成员的指针操作不符合上述要求:&m.a指向的是单个int成员,不属于任何数组,因此p+1只是合法的尾后指针,解引用*(p+1)的行为完全未定义,也不保证指向相邻的m.b成员。

2. 标准布局struct的布局约束

C++20 [class.prop] 章节对标准布局struct的成员布局仅做了最低限度的强制要求:

  • 相同访问控制层级的非静态数据成员,按声明顺序地址递增排列,因此&m.a < &m.b < &m.c必然成立,这也是你可以比较不同成员指针大小的依据。
  • 首个非静态数据成员的地址与struct对象本身的地址相等。
  • 标准允许编译器在任意两个成员之间、struct末尾插入任意字节的填充以满足对齐要求,即使相邻成员是完全相同的基础类型,也没有禁止插入填充的规定。

虽然绝大多数主流编译器在同类型基础成员之间不会插入填充,使得你给出的示例代码在实际运行中大概率能得到预期结果,但这属于编译器实现的特定行为,不是C++标准的强制要求,依赖这种行为的代码不具备可移植性,也不符合标准规范。

合法替代方案

如果需要连续访问多个同类型的属性,最安全的做法是直接将其定义为数组成员:

struct MyStruct {
    int vals[3];
};
static_assert(std::is_standard_layout_v<MyStruct>);

MyStruct m = {0, 1, 2};
int const *p = m.vals;
std::cout << *p << *(p + 1) << *(p + 2) << std::endl;

上述代码完全符合C++标准要求,具备100%的可移植性。

内容的提问来源于stack exchange,提问作者Adrian McCarthy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 02:36:03