2

使用 uint32_t 移动任何类型的项目,然后读回它们是否违反了严格的别名规则?如果是这样,它是否也违反了严格的别名规则,将 uint32_ts 数组 memcpy 到任何类型的数组,然后读回元素?

以下代码示例演示了这两种情况:

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main(void) {
    const char *strings[5] = {
        "zero", "one", "two", "three", "four"
    };
    uint32_t buffer[5];
    int i;

    assert(sizeof(const char*) == sizeof(uint32_t));

    memcpy(buffer, strings, sizeof(buffer));

    //twiddle with the buffer a bit
    buffer[0] = buffer[3];
    buffer[2] = buffer[4];
    buffer[3] = buffer[1];

    //Does this violate strict aliasing?
    const char **buffer_cc = (const char**)buffer;
    printf("Test 1:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", buffer_cc[i]);
    printf("\n");

    //How about this?
    memcpy(strings, buffer, sizeof(strings));
    printf("Test 2:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", strings[i]);
    printf("\n");

    return 0;
}

请忽略我对 32 位平台的假设。此外,如果元素的大小与 uint32_t 不同,我知道填充它们并复制正确数量的 uint32_t。我的问题集中在这样做是否违反了严格的别名。

4

2 回答 2

4

第一个循环在技术上确实uint32_t违反了严格的别名 - 它通过类型的左值访问对象char *。但是,在这种特定情况下,很难看出任何优化器会如何给您带来问题。如果您对其进行了一些更改,那么您将执行以下操作:

printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);

可能会看到相同的字符串打印了两次——因为优化器有权只加载buffer_cc[0]到寄存器中一次,因为第二行只修改了 type 的对象uint32_t

第二个循环,也就是memcpy他们回来,很好。

于 2009-12-18T05:13:30.240 回答
1

buffer_cc[0]strings[3](例如)是引用相同内存位置但类型相同的指针,因此不会违反严格的别名。buffer[0]不是指针,因此不违反严格的别名。取消引用指针时会出现别名优化,所以我不认为这会导致问题。

正如您在代码和问题的最后一段中提到的那样,当指针和 uint32_t 的大小不同时,示例代码中的真正问题就会出现。

此外,您始终可以将 a 别名char*为指向另一种类型而不会违反严格的别名,反之亦然。

于 2009-12-18T05:00:48.567 回答