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

萝らか妹 提交于 2021-01-27 12:51:34

问题


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?

Is this defined behaviour? And, if so, what type of pointer may we use to access the target data after the memcpy?

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

Or must we use uint32_t*, because the type of the source data (the source data copied from by memcpy) is uint_32?

(Personally interested in C++11/C++14. But a discussion of related languages like C would be interesting also.)


回答1:


The C++ standard delegates to C standard:

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

The C standard specifies:

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).

So, to answer your question: Yes, the behaviour is defined.

Yes, uint16_t* is appropriate because uint16_t is the type of the object.


No, the type of the source doesn't matter.

C++ standard doesn't specify such thing as object without declared type or how it would behave. I interpret that to mean that the effective type is implementation defined for objects with no declared type.

Even in C, the source doesn't matter in this case. A more complete version of quote from C standard (draft, N1570) that you are concerned about, emphasis mine:

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. [...]

This rule doesn't apply, because objects in u16 do have a declared type




回答2:


Is this defined behavio[u]r?

Yes. memcpying into a pod is well-defined and you ensured that the sizing is the correct.

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

Yes, of course. u16 is an array of two uint16_ts so it must be accessed as such. Accessing it via a uint32_t* would be undefined behavior by the strict-aliasing rule.

It doesn't matter what the source type was. What matters is that you have an object of type uint16_t[2].


On the other hand, this:

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

is undefined behavior, because now there is an object of a different type whose lifetime has begin at &p and we're accessing it through the wrong type.



来源:https://stackoverflow.com/questions/39595103/memcpy-from-one-type-to-another-type-how-do-we-access-the-destination-afterward

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!