【发布时间】:2020-12-22 17:22:16
【问题描述】:
我偶然发现了reddit thread,其中用户发现了 C++ 标准的一个有趣细节。该线程没有产生太多建设性的讨论,因此我将在这里重述我对问题的理解:
- OP 希望以符合标准的方式重新实现
memcpy - 他们试图通过使用
reinterpret_cast<char*>(&foo)来做到这一点,这是严格别名限制的允许例外,其中允许重新解释为char以访问对象的“对象表示”。 -
[expr.reinterpret.cast] 表示这样做会导致
static_cast<cv T*>(static_cast<cv void*>(v)),因此在这种情况下,reinterpret_cast相当于 static_cast'ing 先到void *然后再到char *。 - [expr.static.cast] 结合[basic.compound]
“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T”的指针类型的纯右值,其中 T 是对象类型,而 cv2 与,或比 cv1 更高的 cv 限定。 [...] 如果原始指针值指向对象 a,并且有一个类型为 T(忽略 cv 限定)的对象 b 可以与 a 指针互转换,则结果是指向 b 的指针。 [...] [强调我的]
现在考虑以下联合类:
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* 会产生一个指向联合体的第一个字符成员(或其对象表示)的指针,而不是指向联合体的对象表示的指针。 union 本身,即它只指向成员。虽然这表面上看起来是相同的,并且对应于相同的内存地址,但标准似乎区分了指针的“值”及其对应地址,因为在抽象 C++ 机器上,指针属于某个对象只要。将其递增到该对象之外(与数组的 end() 比较)是未定义的行为。
OP 因此认为,如果标准强制 char* 与对象的第一个成员而不是整个联合对象的对象表示相关联,则在一次增量后取消引用它是 UB,这允许编译器进行优化,就好像结果 char* 不可能访问 int 成员的以下字节。这意味着不可能合法地访问可与char 成员指针互转换的类对象的完整对象表示。
如果我理解正确的话,如果“union”被简单地替换为“struct”,同样会适用,但我从原始线程中获取了这个例子。
你怎么看?这是标准缺陷吗?是不是有误会?
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
标签: c++ language-lawyer strict-aliasing