I would like to have a runtime-sized buffer (allocated via malloc()
for example) where I can safely access any sufficiently aligned/sized slot as either a uint8_t
uint16_t
uint32_t
or uint64_t
. An implementation of this for a fixed-sized buffer would be fairly straightforward where N
is a compile-time constant:
union Buffer {
uint8_t u8[N * 8];
uint16_t u16[N * 4];
uint32_t u32[N * 2];
uint64_t u64[N];
};
An alternative approach is to have each unit as a union
and then allocate an array of these:
union Buffer {
uint8_t u8[8];
uint16_t u16[4];
uint32_t u32[2];
uint64_t u64;
};
But this approach has shortcomings as described in a different question I asked. Most notably:
union
elements.uint8_t
uint16_t
uint32_t
uint64_t
and then index the pointer beyond the boundary of the first element.So to summarize:
uint8_t
uint16_t
uint32_t
and uint64_t
where I can safely obtain any sufficiently aligned slot in the array as an lvalue of any of the above types.malloc()
/realloc()
/etc.Is there any way to do what I described? Or is the only way to use memcpy()
to safely read/write the elements as the desired types?
If you never want to read memory as a different type than you previously wrote it, then this is trivial. Dynamically allocated memory is intended to be flexible. You do not need arrays at all. Simply convert the pointer to the memory to a pointer to the desired type and use it. Given pv
a void *
that has been assigned from malloc
:
// Convert pointer.
uint16_t *pu16 = p;
// Write element.
pu16[i] = 3;
// Read element.
uint16_t x = pu16[i];
Later, you could write the same memory as uint32_t
or other types. As long as you do not write as one type and read as another, this is defined by the C standard, because the effective type for a write to dynamically allocated memory is the type of the lvalue used to access it, and the effective type for a read is the type last used to write to it, except that character types may always be used and do not change the effective type.
The array arithmetic is guaranteed by the specification for malloc
et al in C 2024 7.24.4.1: “The pointer returned if the allocation succeeds is suitably aligned so that it can be assigned to a pointer to any type of object with a fundamental alignment requirement and size less than or equal to the size requested. It can then be used to access such an object or an array of such objects in the space allocated (until the space is explicitly
deallocated).”
If you do need to read memory as a different type than it was written, and not a character type, then you could use memcpy
to copy the bytes from the memory into an object of the desired type.