【问题标题】:Aliasing accesses through a std::bit_cast()ed pointer通过 std::bit_cast()ed 指针对访问进行别名访问
【发布时间】:2021-08-18 07:08:08
【问题描述】:

违反严格别名规则会产生未定义的行为,例如当通过网络将结构发送到 char 缓冲区时,然后该 char 指针是 C-style/std::reinterpret_cast() 强制转换为结构指针。

C++ std::bit_cast() function 看起来可以用于以(实现?)定义的方式转换此类指针,即不违反严格别名规则。

例子:

#include <sys/types.h>
#include <netinet/in.h>

#include <bit>

int get_sock_addr(const struct sockaddr *a)
{
    struct sockaddr_in *x = std::bit_cast<struct sockaddr_in*>(a);
    return x->sin_addr.s_addr;
}

所以get_sock_addr() 的调用者不知何故获得了一个sockaddr 指针,并确定它实际上指向了一个sockaddr_in 结构。

那么,这种通过std::bit_cast() 进行的指针转换是一个有效的用例吗?

或者它是否也会以某种方式产生未定义的行为?

如果是定义的行为,标准是否将这种指针转换归类为实现定义的行为?


std::bit_cast() proposal 提到:

如果没有值表示对应于 To 的对象表示,则返回值未指定。

那么,在不同的指针表示不兼容以致不能相互对应的情况下,是否可以使用符合标准的编译器?

【问题讨论】:

  • 您的示例及其假设是reinterpret_cast 的标准有效用例。
  • @DavisHerring 嗯,这真的取决于在调用示例 get_sock_addr 函数之前/之后对 sockaddr 指针做了什么,对吧?例如,对于sockaddr *a = getfromsomewhere(); if (a-&gt;sa_family == AF_INET) addr = get_sock_addr(a); ... } ... 之类的东西,sockaddr_in 对象是通过严格别名规则未涵盖的类型的 2 个别名指针访问的,对吗?
  • 在问题中你只是说“它实际上指向一个sockaddr_in 结构”。您刚刚提供的代码试图验证该假设,但实际上与它不兼容(不幸的是,因为这是传统 C 接口的设计方式)。 common-initial-subsequence 规则旨在允许这种标记,但它们需要一个实际的联合。
  • @DavisHerring 很好,在问题中我说调用者'已经确定它实际上指向一个 sockaddr_in 结构'。因此,我在上一条评论中给出的代码是此确定步骤的一种可能实现方式。当然,可以说,在原始示例代码中包含该步骤会成为一个更好的示例。
  • 我们达成了激烈的协议。该代码是确定隐藏在指针后面的实际类型的明显方法——但 C++ 不允许您这样做,因为它涉及使用对象作为不同的类型来进行确定。

标签: c++ language-lawyer c++20 strict-aliasing


【解决方案1】:

转换指针值是无关紧要的。重要的是对象。你有一个指向 X 类型对象的指针,但指针的类型是 Y。试图通过指向不相关类型 Y 的指针/引用来访问 X 类型的对象是 UB 的来源。

您如何获得这些指针几乎无关紧要。所以bit_cast在这方面并不比reinterpret_cast好。

如果那里没有sockaddr_in,那么你不能假装有一个。但是,C++20 中的 implicit object creation 可能已经解决了这个问题,具体取决于您的代码。如果是这样,那么它仍然与你如何获得指针无关。

【讨论】:

  • 关于对象创建的要点。前段时间想知道为什么我在 C++11 标准文档中找不到 C 有效类型的概念。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多