我是否正确应用了严格别名规则?

Have I applied the rule of strict aliasing correctly?

我当前的(简化的)缓冲区 API 看起来像这样:

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;
}

但是,在刷新了我对 C 中严格别名规则的了解之后,我对这个用例不太确定:

    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, '[=11=]');

我认为我应该在缓冲区结构中使用 void * 并使用 (char *) 转换来访问基础数据:

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;
}

因为 char *unsigned char *signed char * 总是假设为其他数据类型的别名。

uint8_t *(按照标准)

就不能这么说了

如果 CHAR_BIT8 那么这个带有 (void *) 的调整后的代码应该和 uint8_t 版本完全一样。

现在问题来了:我是否正确应用了严格别名规则?

如果 uint8_tunsigned char 不同,则为 UB。假设 uint8_t 存在,则可能性很小,因为

但是,标准并没有明确要求uint8_tunsigned char是同一类型。因此,它是由实现定义的。

考虑应用以下线程中的解决方案来检查上述类型是否相同。

最好使用char*/unsigned char*来访问数据。但是,如果代码的重构很麻烦,那么只需添加检查类型 uint8_tunsigned char 是否相同,如果不相同则拒绝编译。