3 ms·
The memcpy() from the "specific" slice to the "generic" slice in grow() is technically UB I think. Those slice structures are not the same types. Furthermore,
by jstimpfle 3y ago
The memcpy() from the "specific" slice to the "generic" slice in grow() is technically UB I think. Those slice structures are not the same types.
Furthermore, a void pointer can be implemented "differently" than a typed pointer. The size of pointers can (theoretically) be different for different types. Any typed pointer roundtrips safely to a void pointer and back, but the inverse doesn't necessarily hold.
Then again, not sure which implementations might make problems here. For example, keeping a typed version of a void pointer returned by malloc() and using it to free() later is common practice.
- amalcon 3y agoMemcpy is IIRC one of two ways to do type-punning (reinterpretation of bytes as a different type) without undefined behavior in C, and the only one in C++. The other one in C is using a union type (which results in undefined behavior in C++). The behavior is implementation-defined, for obvious reasons, but that's not the same as undefined.
- PhilipRoman 3y agoMemcpy between structures is quite safe (as opposed to simply casting between pointers which is what usually triggers the type based aliasing rules)
- jstimpfle 3y agoCasting to a void pointer is perfectly fine though, so maybe that should be the preferred way to pass the pointer to the allocation. (I would also be interested to know how casting the void pointer returned from generic allocation routines to some typed pointer is justified).
- PhilipRoman 3y agoC (at least c11, probably 99 as well) has a concept called "effective type". Quoting 6.5, paragraph 6: If a value is store into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. (the same applies to memcpy and memmove) For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access. Paragraph 7 then lists all valid ways that an object can be accessed. TL;DR the lvalue must be [qualified/signed/unsigned] effective type of the object OR char OR union including the correct type. Something does feel missing though as while this explains memory obtained from routines like malloc which initially has no effective type, I cannot find any rule saying it is permissible to treat char arrays as structures (their effective type is an array of char, so they cannot be said to "have no declared type").