我被下面一段关于cpprreference(来源(的类型别名的内容弄糊涂了:
每当试图通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下情况之一为真,否则行为是未定义的:
- AliasedType和DynamicType相似
- AliasedType是DynamicType的有符号或无符号变体(可能是cv限定的(
-
AliasedType是
std::byte
、char
或unsigned char
:这允许将任何对象的对象表示检查为字节数组
假设我有一个大小大于1字节的平凡类型(如标量(的对象。通过什么方式(如果有的话(,我可以通过指向不同类型的指针修改对象的字节表示,而不调用未定义的行为?例如:
int x = 5, y = 10;
std::byte* x_bytes = reinterpret_cast<std::byte*>(&x);
//#1: replacing the entire representation:
std::memcpy(x_bytes, &y, sizeof(int));
//#2: changing a random byte in the representation:
x_bytes[0] = (std::byte)3;
这两种操作都允许,还是只允许#1
问题是我不知道如何解释我引用的那段话。这三个项目符号是规则的例外;每当试图读取或修改存储的值[…]时,行为是未定义的",这意味着如果其中一个项目符号适用,则允许读取和写入。然而,第三个子弹只提到了"对象表示的检查">,这意味着只读访问
我试图找到一个合适的标准页面来更详细地描述这个问题,但我一直没能找到,所以这就是我所拥有的与这个问题相关的全部内容。
这两种操作都允许吗
是。没有规定你必须全部修改或什么都不修改。允许修改单个字节。
然而,第三个项目符号只提到";对象表示的检查";,这意味着只读访问。
标准规则没有使用这样的措辞。这是最新草案中的规则:
〔basic.lval〕
如果程序试图通过类型与以下类型之一不相似的glvalue访问对象的存储值,则行为未定义:
- 对象的动态类型
- 与对象的动态类型相对应的有符号或无符号类型,或者
- char、无符号char或std::字节类型
访问定义为:
[defns.access]
⟨执行时间动作⟩读取或修改对象的值
当然,从可移植性的角度来看,按索引顺序修改字节是非常可疑的,因为不同的系统以不同的顺序存储字节,因此您将在不同的系统上修改具有不同重要顺序的字节。
不同系统上的不同行为通常是不可取的。