您可以通过 char* 访问任何对象的对象表示吗?

Can you access the object representation of any object through a char*?

我偶然发现了一个 reddit thread,用户在其中发现了 C++ 标准的有趣细节。该线程没有产生太多建设性的讨论,因此我将在这里重述我对问题的理解:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. [...] if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b. [...] [emphasis mine]

现在考虑以下联合 class:

union Foo{
    char c;
    int i;
};
// the OP has used union, but iiuc,
// it can also be a struct for the problem to arise.

OP 因此得出结论,在这种情况下将 Foo* 重新解释为 char* 会产生指向联合的第一个 char 成员(或其对象表示)的指针,而不是到联合本身的对象表示,即它仅指向 成员 。虽然这在表面上看起来是相同的,并且对应于相同的内存地址,但标准似乎区分了指针的“值”及其对应的地址,因为在抽象 C++ 机器上,指针属于某个对象只要。将它递增到该对象之外(与数组的 end() 相比)是未定义的行为。

OP 因此认为,如果标准强制 char* 与对象的第一个成员而不是整个联合对象的对象表示相关联,则在一次递增后取消引用它是 UB,这允许编译器进行优化,就好像结果 char* 不可能访问 int 成员的后续字节一样。这意味着不可能合法地访问 class 对象的完整对象表示,该对象可与 char 成员进行指针互换。

如果我理解正确的话,如果“union”被简单地替换为“struct”,同样适用,但我从原始线程中获取了这个例子。

你怎么看?这是标准缺陷吗?是误读吗?

This video,@KonradRudolph 在评论(现在聊天)中链接可能是问题的答案。

在 40 分钟左右,ISO C++ 委员会成员 Timur Doumler 讨论了访问字节表示的可能性。总结是,除 memcpy 之外的任何访问字节表示的尝试都是 UB。如果不使用 UB,OP 中的情况甚至不会出现,因为使用指向对象(如数组)或对其进行任何指针运算的行为本身就是 UB,因为这些操作仅 well-defined 当就抽象机而言,处理实际的数组对象。

此外,虽然将指针重新解释为 char* 本身并不违反别名规则,但从技术上讲并不能保证生成的 char* 将指向对象的第一个字节。

访问字节表示的唯一合法方法是 memcpy 将对象转换为 char 数组。这意味着重新实现 memcpy 是不可能的。

Timur Doumler 还将此描述为一个有望在 C++23 中修复的措辞缺陷,并提交了一篇论文,提出了对此的修复建议。