My current (simplified) buffer API looks like this:
typedef struct {
size_t offset;
size_t size;
uint8_t *data;
} my_buffer;
// Writes an unsigned int 8 to the buffer
bool my_buffer_write_u8(my_buffer *buffer, uint8_t value) {
if (buffer->offset >= buffer->size) return false;
buffer->data[buffer->offset] = value;
++buffer->offset;
return true;
}
However, after refreshing my knowledge about the strict aliasing rule in C I'm not so sure about this use case:
char string[32];
my_buffer buffer;
buffer.size = sizeof(string);
buffer.data = string; // <-- I think this violates the strict aliasing rule
buffer.offset = 0;
// the function calls access buffer.data which is defined to be `uint8_t *` and not `char *`
// in other words, I'm manipulating a `char *` through a `uint8_t *`:
// even though uint8_t is almost always unsigned char, it is nevertheless not the same as unsigned char
my_buffer_write_u8(&buffer, 'h');
my_buffer_write_u8(&buffer, 'e');
my_buffer_write_u8(&buffer, 'l');
my_buffer_write_u8(&buffer, 'l');
my_buffer_write_u8(&buffer, 'o');
my_buffer_write_u8(&buffer, '\0');
I think I should be using void *
in the buffer struct and use a (char *)
cast to access the underlying data:
typedef struct {
size_t offset;
size_t size;
void *data;
} my_buffer;
// Writes an unsigned int 8 to the buffer
bool my_buffer_write_u8(my_buffer *buffer, uint8_t value) {
if (buffer->offset >= buffer->size) return false;
unsigned char *data = (unsigned char *)buffer->data;
data[buffer->offset] = value;
++buffer->offset;
return true;
}
Because char *
, unsigned char *
and signed char *
are always assumed to alias other datatypes.
The same cannot be said about uint8_t *
(according to the standard that is)
If CHAR_BIT
is 8
then this adjusted code with (void *)
should do exactly the same as with the uint8_t
version.
Now to the question: have I applied the rule of strict aliasing correctly?