Home > Mobile >  Have I applied the rule of strict aliasing correctly?
Have I applied the rule of strict aliasing correctly?

Time:10-26

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?

CodePudding user response:

It would be UB if uint8_t was different from unsigned char.Assuming uint8_t exists it is very unlikely because

However, the standard does not explicitly require that uint8_t is the same type as unsigned char. Therefore it's rather implementation defined.

Consider applying solution from following thread to check it forementioned types are the same. How to assert two types are equal in c?

It is preferable to use char*/unsigned char* for accessing the data. However, if refactoring of the code would be cumbersome then just add a check if the types uint8_t and unsigned char are the same and reject compilation if not.

  • Related