gpt4 book ai didi

c++ - memcpy/memmove 到 union 成员,这是否设置了 'active' 成员?

转载 作者:IT老高 更新时间:2023-10-28 21:37:01 28 4
gpt4 key购买 nike

重要的澄清:一些评论者似乎认为我是从 union 复制的。仔细查看 memcpy,它从一个普通的旧 uint32_t 地址复制而来,该地址不包含在 union 中。另外,我正在(通过 memcpy)复制到 union 的特定成员(u.a16&u.x_in_a_union,而不是直接复制到整个 union 本身 (&u)

C++ 对 union 非常严格 - 只有当该成员是最后写入的成员时,您才应该从该成员中读取:

9.5 Unions [class.union] [[c++11]] In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

(当然,编译器不会跟踪哪个成员处于事件状态。由开发人员确保他们自己跟踪)


更新:以下代码块是主要问题,直接反射(reflect)问题标题中的文本。如果这段代码没问题,我会跟进其他类型,但我现在意识到这第一段代码本身很有趣。

#include <cstdint>
uint32_t x = 0x12345678;
union {
double whatever;
uint32_t x_in_a_union; // same type as x
} u;
u.whatever = 3.14;
u.x_in_a_union = x; // surely this is OK, despite involving the inactive member?
std::cout << u.x_in_a_union;
u.whatever = 3.14; // make the double 'active' again
memcpy(&u.x_in_a_union, &x); // same types, so should be OK?
std::cout << u.x_in_a_union; // OK here? What's the active member?

紧接在此上方的代码块可能是评论和答案中的主要问题。事后看来,我不需要在这个问题中混合类型!基本上,假设类型相同,u.a = b 是否与 memcpy(&u.a,&b, sizeof(b)) 相同?


首先,一个相对简单的 memcpy 允许我们将 uint32_t 读取为 uint16_t 的数组:

#include <cstdint> # to ensure we have standard versions of these two types
uint32_t x = 0x12345678;
uint16_t a16[2];
static_assert(sizeof(x) == sizeof(a16), "");
std:: memcpy(a16, &x, sizeof(x));

确切的行为取决于您平台的字节序,您必须注意陷阱表示等。但这里普遍同意(我认为?感谢反馈!),注意避免有问题的值,上面的代码可以在正确的平台上的正确上下文中完全符合标准。

(如果您对上述代码有疑问,请相应地评论或编辑问题。我想确保在继续执行下面的“有趣”代码之前,我们有上述的无争议版本。 )


如果,且仅当,以上两段代码都不是-UB,那么我想将它们组合如下:

uint32_t x = 0x12345678;
union {
double whatever;
uint16_t a16[2];
} u;
u.whatever = 3.14; // sets the 'active' member
static_assert(sizeof(u.a16) == sizeof(x)); //any other checks I should do?
std:: memcpy(u.a16, &x, sizeof(x));

// what is the 'active member' of u now, after the memcpy?
cout << u.a16[0] << ' ' << u.a16[1] << endl; // i.e. is this OK?

union 的哪个成员 u.whateveru.a16 是“活跃成员”?


最后,我自己的猜测是,我们在实践中关心这个的原因是优化编译器可能没有注意到 memcpy 发生了,因此做出错误的假设(但允许的假设,按照标准)关于哪个成员是事件的以及哪些数据类型是“事件的”,因此会导致别名错误。编译器可能会以奇怪的方式重新排序 memcpy这是对我们为什么关心这个问题的恰当总结吗?

最佳答案

我对标准的解读是,只要类型可轻松复制std::memcpy 都是安全的。

从 9 个类中,我们可以看到 union 是类类型,因此 trivially copyable 适用于它们。

A union is a class defined with the class-key union; it holds only one data member at a time (9.5).

A trivially copyable class is a class that:

  • has no non-trivial copy constructors (12.8),
  • has no non-trivial move constructors (12.8),
  • has no non-trivial copy assignment operators (13.5.3, 12.8),
  • has no non-trivial move assignment operators (13.5.3, 12.8), and
  • has a trivial destructor (12.4).

trivially copyable 的确切含义在 3.9 类型中给出:

For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value.

For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making up obj1 are copied into obj2, obj2 shall subsequently hold the same value as obj1.

该标准还给出了两者的明确示例。

因此,如果您要复制整个 union ,答案肯定是肯定的,事件成员将与数据一起“复制”。 (这是相关的,因为它表明 std::memcpy 必须 被视为更改 union 的事件元素的有效方法,因为明确允许使用它 union 复制。)

现在,您改为复制到 union 的成员中。该标准似乎不需要任何特定的方法来分配给 union 成员(并因此使其处于事件状态)。它所做的只是指定(9.5)

[ Note: In general, one must use explicit destructor class and placement new operators to change the active member of a union. — end note]

当然,因为 C++11 允许在 union 中使用非平凡类型的对象。请注意前面的“一般”,它非常清楚地表明在特定情况下允许使用其他更改事件成员的方法;我们已经知道是这种情况,因为明确允许分配。当然,没有禁止使用 std::memcpy,否则它的使用是有效的。

所以我的回答是肯定的,这是安全的,是的,它会改变事件成员。

关于c++ - memcpy/memmove 到 union 成员,这是否设置了 'active' 成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39763548/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com