- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
重要的澄清:一些评论者似乎认为我是从 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.whatever
或 u.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 typeT
, the underlying bytes (1.7) making up the object can be copied into an array ofchar
orunsigned char
. If the content of the array ofchar
orunsigned char
is copied back into the object, the object shall subsequently hold its original value.For any trivially copyable type
T
, if two pointers toT
point to distinctT
objectsobj1
andobj2
, where neitherobj1
norobj2
is a base-class subobject, if the underlying bytes (1.7) making upobj1
are copied intoobj2
,obj2
shall subsequently hold the same value asobj1
.
该标准还给出了两者的明确示例。
因此,如果您要复制整个 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/
下面的代码片段显示了 memmove() 的实现。 void my_memmove(void* dest, const void* src, size_t size) { unsigned i
在 CLRS 第 2 章中有一个练习,询问是否可以将插入排序的最坏情况运行时间改进为 O(n lg n)。我看到了this question发现做不到。 最坏情况下的复杂性无法改善,但与单独移动数组元
我正在使用memmove(),但目标似乎正在覆盖源,或者也许我不明白覆盖是什么。我有一个 char 数组(目标),然后是一个指向目标的指针,该指针位于 vector 内部。 char destinat
根据 C11 N1570 standard draft : 7.24.2.2 “memmove 函数”: The memmove function copies n characters from t
移动 2D double 组时遇到问题。在下面的代码中,我有 双权重[wt][2] 我可以将 Weights[0][0] 移动到 Weights[0][1],但只能在要移动的字节数末尾添加“*2”。为
我正在尝试读取和处理二进制文件。由于其编写方式,我以字符数组的形式读取它。当我处理完数据后。我将剩余数据移至字符缓冲区的开头以避免缓冲区溢出。我正在为此使用 memmove,但这似乎会导致堆增长,这表
假设有一个指向浮点值数组的指针:float *source; 并且我们知道它的大小为 int sourcesize; 有一个已经实现的函数,它从 inputVec 添加一个元素到 souce 数组:
我正在使用 memmove 将 std::string 元素向右移动一位。目的地的第一个地点是唯一一个乱七八糟、堆满垃圾的地方。我使用 memmove 而不是 strcpy 因为我在需要模板的类中使用
假设我有一个这样的整数数组 #define MAX 5 int bar [MAX] = {0}; int foo [MAX] = {3,1,0,0,0}; 现在我想移动这个数组,使所有空条目都在左边,
我想使用返回结果字符串的函数连接两个字符串。它会是这样的: char *String_Concat (char *String_1, char *String_2) { char *Strin
memmove 并没有真正移动内存,不是吗?它只是将内存从一个区域复制到另一个区域,并允许这两个区域重叠。我问这个问题是因为我只是想知道为什么这个 fnc 以非常误导的方式被调用。 因为我知道当某物从
我正在阅读关于 memcpy 和 memmove 的 c++ 引用资料,它们似乎在做同样的事情,除了 memmove 有一个特定的think called(允许目的地和来源重叠)。 什么是重叠以及何时
标准库提供了std::copy,可以看作是C的memcpy()的泛化/类化。它还保持了 memcpy() 的要求,范围 [first, last) 与范围 [d_first , d_first + s
我编写了以下函数,将给定的完整路径拆分为目录、文件名和扩展名。 #include #include #include struct path_info { char *directory
我在 StackOverflow 上进行了搜索,但找不到我想要做的事情。我想将指针 Items 复制到指针 COPYTO。然后就可以调用COPYTO->x。 #include typedef str
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Bus error troubleshooting 要从字符串中删除重复项,这是我编写的程序: #include #
当我编写时,我的代码不会崩溃: char s[44] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; memmove(s, "asdf", 5); 但
我正在尝试移动可能重叠的内存,对 *src 和 *dst 使用负增量或正增量,并且不使用大型临时缓冲区。 我正在尝试为 memmove() 函数找到一个有效的替代方案,大致如下: smart_memm
我试图了解 memmove 是如何工作的。我举一个例子,我以这种方式在内存中保存数据。 Start at 0 First Memory Block(A) of size 10 Hence A->(0,
我有以下代码,我试图在其中创建一个长度为 7 字节的缓冲区,然后将网络字节顺序中的整数与缓冲区中的 char 数组一起放入,最后我不应该有 Null 字符我的 sprintf() 缓冲区,所以我使用
我是一名优秀的程序员,十分优秀!