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

通过unsigned char别名访问对象:加载存储行为及断言有效性问询

C++17数组别名访问:断言会触发吗?修改是UB吗?

咱们先拆解第一个代码片段的问题:

第一个断言assert(*alias_to_array_s=='X')会不会触发?

首先得明确C++17里的两个核心规则:

  • 严格别名规则有个关键例外:根据[basic.lval]/8,任何对象的存储值都可以通过unsigned char类型的指针读取,不管原对象的具体类型是什么。
  • 虽然数组和它的首元素不是指针可互转换的([basic.compound]中明确了这一点),但&s(数组的地址)和&s[0](首元素的地址)在数值上完全一致——把指向数组的指针pointer_to_array_s强转成unsigned char*后,alias_to_array_s的地址值就是数组s的起始地址,也就是首元素'X'所在的地址。

这里的核心是,用unsigned char*访问的是数组对象的存储字节,而数组的第一个字节正好就是首元素'X'的字节。严格别名的unsigned char例外允许这种访问,所以这个断言绝对不会触发,行为是完全定义良好的。

第二个场景:修改别名后,assert(s[0]=='Y')会触发吗?修改本身是UB吗?

再看第二个代码片段:

*alias_to_array_s='Y'; //UB? 
assert(s[0]=='Y');//may fire? 

同样套用[basic.lval]/8的规则:用unsigned char指针修改对象的存储字节也是允许的——这属于严格别名规则的合法例外。数组s的存储和它的首元素s[0]的存储完全重叠(数组的起始地址就是首元素的地址,数组的存储包含首元素的所有字节),所以修改*alias_to_array_s本质上就是修改了s[0]对应的存储字节。

结论很明确:

  • *alias_to_array_s='Y'; 不是未定义行为,完全符合标准规则。
  • assert(s[0]=='Y'); 也不会触发,因为直接访问s[0]读取的就是被修改后的字节值。

别被“alias_to_array_s不是指向s[0]的有效指针”这个细节迷惑——严格别名的unsigned char例外不要求指针必须指向某个子对象,只要求你是在访问目标对象的存储字节。这里我们访问的是数组对象s的存储,而它的第一个字节就是s[0]的内容,所以操作完全合法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:51:58