JMC*_*JMC 10 c++ strict-aliasing language-lawyer
我偶然发现了一个reddit 线程,用户在其中发现了 C++ 标准的一个有趣细节。该线程没有产生太多建设性的讨论,因此我将在这里复述我对问题的理解:
memcpy符合标准的方式重新实现reinterpret_cast<char*>(&foo)这一点,这是严格别名限制的允许例外,其中允许重新解释 aschar访问对象的“对象表示”。static_cast<cv T*>(static_cast<cv void*>(v)),所以reinterpret_cast在这种情况下等价于 static_cast'ing first tovoid *然后 to char *。“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定,或比 cv1 更高的 cv 限定。[...]如果原始指针值指向对象 a,并且存在 T 类型的对象 b(忽略 cv 限定)与 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.
Run Code Online (Sandbox Code Playgroud)
从而OP已经到该重新解释一个结论Foo*作为char*在这种情况下产生一个指针指向联合的第一个字符部件(或它的对象表示),而不是向联合本身的对象表示,即,其指向仅与会员。虽然表面上看起来是一样的,并且对应于相同的内存地址,但标准似乎区分了指针的“值”与其对应的地址,因为在抽象的 C++ 机器上,指针属于某个对象只要。将它增加到该对象之外(与数组的 end() 相比)是未定义的行为。
因此,OP 认为,如果标准强制将char*与对象的第一个成员关联,而不是与整个联合对象的对象表示相关联,则在一次增量后取消引用它是 UB,这允许编译器进行优化,就好像结果不可能一样char*永远访问 int 成员的以下字节。这意味着不可能合法地访问与char成员指针可互转换的类对象的完整对象表示。
同样的,如果我理解正确,如果“联合”被简单地替换为“结构”,但我从原始线程中获取了这个例子。
你怎么认为?这是标准缺陷吗?这是一种误解吗?
这个视频@KonradRudolph 在评论(现在是聊天)中链接的
在 40 分钟左右,ISO C++ 委员会成员 Timur Doumler 讨论了访问字节表示的可能性。总结是,任何访问字节表示的尝试,除了memcpyUB 之外,任何访问字节表示的尝试。如果不使用 UB,OP 中的情况就不会出现,因为使用指向对象(如数组)的指针或对其进行任何指针算术的行为本身就是 UB,因为这些操作仅在处理时才明确定义就抽象机而言,实际的数组对象。
此外,虽然将指针重新解释为 achar*本身并不违反别名规则,但从技术上讲并不能保证结果char*将指向对象的第一个字节。
访问字节表示的唯一合法方法是将memcpy对象转换为 char 数组。这意味着重新实现memcpy是不可能的。
Timur Doumler 还将此描述为措辞缺陷,有望在 C++23 中修复,并提出了一篇论文,提出了对此的修复方案。
| 归档时间: |
|
| 查看次数: |
226 次 |
| 最近记录: |