reintrepret_cast to char* 修改char数组时是否定义好?

Is reintrepret_cast to char* well defined when the char array is modified?

从套接字接收预期消息时考虑以下示例:

struct myData {
    uint8_t type;
    int value;
}

myData readFromSocket(int socketFD) {
    myData data{};
    ssize_t bytes = recv(socketFD, reinterpret_cast<char*>(&data), sizeof(myData), 0);
    if(bytes == sizeof(myData))
        return data;
    return myData{};
}

在这个例子中,我不清楚行为是否定义明确。

根据 reintrpret_cast on cppreference.com检查 的行为已明确定义,因为 char 的对齐不如 myData 的对齐严格,而且强制转换为 char指针。我不清楚检查是否只针对读取,或者是否包括对转换指针的写入。

5)解释中:

Any object pointer type T1* can be converted to another object pointer type cv T2*. This is exactly equivalent to static_cast<cv T2*>(static_cast<cv void*>(expression)) (which implies that if T2's alignment requirement is not stricter than T1's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules (see below)

还有类型别名的第三点:

AliasedType is std::byte (since C++17), char, or unsigned char: this permits examination of the object representation of any object as an array of bytes.

我已经测试了与上面类似的代码,没有任何问题,但是由于这一切都归结为编译器做了哪些优化,我发现很难给出一个确切的例子来说明这可能会失败。

This article 提到在另一个方向上转换,即从 char*myData 会出现未定义的行为,并建议使用 memcpy()。我的假设是得出这个结论是因为转换不在类型别名规则的范围内。

然而 this mail thread 怀疑 memcpy(),根据标准,应该提供保证(见下面的引用)并且在没有阅读标准的情况下我倾向于同意,因为它看起来像memcpy()recv().

进行了相同的转换

In the C++ community, the current thinking is that memcpy allows to type pun, but IIRC the C++ standard is actually not even clear as for why this is the case, and in its current writing it might be that there is actually no way.

无论如何,如果有人对此有所了解并能提供一些线索,我将不胜感激。我对这件事的兴趣更多是学术上的,而不是实践上的。我用 c++17 标记了它,因为这就是我的工作,欢迎对其他标准的见解。

C++ 标准在 [basic.lval]/p8:

中指定了别名规则

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
. . .
— a char, unsigned char, or std​::​byte type.

术语访问[defns.access]:

中指定

⟨execution-time action⟩ to read or modify the value of an object

除此之外,没有其他规则表明别名有效 one-way。

所以我们可以得出结论,别名是双向工作的,代码是可以的。

但是请注意,如果被覆盖的对象包含const个成员,那么覆盖后应该std::launder它,否则允许编译器假定const个成员永远不会改变.