首页 > 解决方案 > 在 C++ 中通过指向其字节表示的指针修改对象有哪些限制?

问题描述

我对以下关于 cppreference (source)的类型别名的段落感到困惑:

每当尝试通过 AliasedType 类型的 glvalue 读取或修改 DynamicType 类型的对象的存储值时,除非满足以下条件之一,否则该行为是未定义的:

考虑我有一个大小大于 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?
问题是我不知道如何解释我引用的段落。这三个项目符号是“每当尝试读取或修改存储的值 [...] 时,行为是未定义的”规则的例外,这意味着如果其中一个项目符号适用,则允许读取和写入. 然而,第三个项目符号只提到了“对象表示的检查”,这意味着只读访问。
我试图找到一个适当的标准页面来更详细地描述这个问题,但我没能找到,所以这就是我所拥有的与问题相关的全部内容。

标签: c++typeslanguage-lawyerundefined-behaviorc++20

解决方案


是否允许这两种操作

是的。没有规则说您必须全部修改或全部修改。允许修改单个字节。


但是,第三个项目符号只提到“检查对象表示”,这意味着只读访问。

标准规则不使用这样的措辞。这是最新草案中的规则:

[基本.lval]

如果程序尝试通过类型与以下类型之一不相似的泛左值访问对象的存储值,则行为未定义:

  • 对象的动态类型,
  • 对应于对象动态类型的有符号或无符号类型,或
  • char、unsigned char 或 std​::​byte 类型。

访问定义为:

[defns.access]

⟨执行时动作⟩读取或修改对象的值


当然,从可移植性的角度来看,通过索引顺序修改字节是非常可疑的,因为不同的系统以不同的顺序存储它们的字节,因此您将在不同的系统上修改具有不同重要性顺序的字节。

不同系统上的不同行为通常是不可取的。


推荐阅读