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

C++标准布局类取成员地址偏移访问相邻成员是否合法

结论

你提出的观点完全符合C++标准规定:题目中从成员子对象obj的地址出发、越过obj的内存边界访问外层结构体其他成员的操作,不属于良定义行为,即使X是标准布局类也不例外。

示例涉及的代码如下:

struct X {
    int num;
    Object obj; // also standard layout
    char buf[512];
};

X x;
char* p = reinterpret_cast<char*>(&x.obj) + sizeof(Object);
*((int*)p) = 1234; // write an int into buf
标准规则依据
  • 指针算术的边界约束:C++标准对指针加减运算的合法范围有严格限定:当对类型为T*的指针做偏移运算时,该指针会被视作指向一个长度为1的T类型数组的首元素,运算结果只有落在这个数组的存储范围内、或是刚好指向数组末尾后一位的哨兵位置时,指针运算本身才是合法的;超出这个范围得到的指针值不具备标准层面的语义,属于未定义行为。
    对应到示例代码:&x.obj是指向Object类型成员子对象的指针,它对应的“长度为1的数组”就是obj自身的存储,对它做+ sizeof(Object)的偏移后,得到的指针已经越过了obj对应的合法哨兵位置,指针推导过程本身就已经触发未定义行为,和后续是否解引用无关。
  • 标准布局规则不提供跨成员指针访问的豁免:标准确实规定标准布局类的非静态数据成员按声明顺序地址递增,也允许在结构体指针和首个非静态成员指针之间做合法转换,但这些规则仅定义了成员的地址相对关系,从未授予从某一个成员子对象的指针出发、越过子对象边界访问其他成员的权限。
    你提到的“取X实例地址转char*遍历整个对象内容合法”,本质是因为此时指针运算的基准是x这个完整对象,整个X实例的存储区间都属于该完整对象的合法范围;一旦把指针基准换成内部的成员子对象,合法访问范围就立刻收缩到该子对象自身的存储区间,和外层对象的其他部分没有语义上的关联。
  • 额外的别名规则违规:示例中最后将偏移得到的char*强转为int*并写入的操作,还单独触发了严格别名规则违规:写入位置属于char类型数组buf的存储范围,该位置不存在存活的int类型对象,直接通过int*类型左值写入同样属于未定义行为。
常见误区澄清

哪怕obj成员之后没有任何结构体填充,偏移得到的指针数值上刚好等于x.buf的起始地址,上述操作依然是未定义的。C++的指针合法性不是只看内存地址的数值相等,而是和指针推导时绑定的基准对象范围强绑定——同样的地址值,如果是从外层X实例的指针加offsetof(X, buf)得到,就是合法的;如果是从obj成员的指针偏移得到,就不具备合法访问buf的语义。

内容的提问来源于stack exchange,提问作者Chris Uzdavinis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:01:05