从一种类型到另一种类型的 memcpy。之后我们如何访问目的地?

memcpy from one type to another type. How do we access the destination afterwards?

uint32_t u32 = 0;
uint16_t u16[2];
static_assert(sizeof(u32) == sizeof(u16), "");
memcpy(u16, &u32, sizeof(u32)); // defined?
// if defined, how to we access the data from here on?

这是定义的行为吗?并且,如果是这样,我们可以使用什么类型的指针来访问 memcpy 之后的目标数据?

我们必须使用 uint16_t*,因为它适合 u16 声明的 类型吗?

还是一定要用uint32_t*,因为源数据(memcpy复制过来的源数据)的类型是uint_32

(个人对 C++11/C++14 感兴趣。但是讨论 C 等相关语言也会很有趣。)

Is this defined behavio[u]r?

是的。 memcpy加入广告连播是明确的,您确保大小是正确的。

Must we use uint16_t*, because that suitable for the declared type of u16?

当然可以。 u16 是一个包含两个 uint16_t 的数组,因此必须这样访问它。通过 uint32_t* 访问它是严格别名规则未定义的行为。

源类型是什么并不重要。重要的是你有一个 uint16_t[2] 类型的对象。


另一方面,这个:

uint32_t p;
new (&p) uint16_t(42);
std::cout << p;

是未定义的行为,因为现在有一个不同类型的对象,其生命周期从 &p 开始,我们通过错误的类型访问它。

C++标准委托给C标准:

The contents and meaning of the header <cstring> are the same as the C standard library header <string.h>.

C标准规定:

7.24.1/3 For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).

因此,回答您的问题:是的,行为已定义。

是的,uint16_t*是合适的,因为uint16_t是对象的类型。


不,源的类型无关紧要。

C++ 标准没有指定没有声明类型的对象或它的行为方式。我将其解释为有效类型是为没有声明类型的对象定义的实现。

即使在 C 中,源代码在这种情况下也不重要。你关心的C标准(草案,N1570)的更完整版本,强调我的:

6.5/6 [...] If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. [...]

此规则不适用,因为 u16 中的对象确实具有已声明的类型