代码之家  ›  专栏  ›  技术社区  ›  Joey Adams

移动一种类型和另一种类型的值是否违反了严格的别名?

  •  2
  • Joey Adams  · 技术社区  · 15 年前

    是否违反了严格的别名规则,使用uint32移动任何类型的项目,然后读取它们?如果是这样,它是否也违反了从uint32数组到任何类型数组的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的正确数字。我的问题是这样做是否违反了严格的别名。

    2 回复  |  直到 15 年前
        1
  •  4
  •   caf    15 年前

    第一环 技术上违反了严格的混叠-它访问 uint32_t 通过类型的左值的对象 char * . 然而,很难看出在这种特定的情况下,任何乐观主义者都会给你带来什么问题。如果你对它做了一些改动,你会做如下的事情:

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

    可以 看到同一个字符串打印两次-因为乐观主义者将在其权利范围内只加载 buffer_cc[0] 因为第二行只修改一个类型的对象 UIT32 .

    第二个循环, memcpy 他们回来了,很好。

        2
  •  1
  •   outis    15 年前

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

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

    此外,您可以始终使用别名A char* 指向另一个类型,而不违反严格的别名,但反之亦然。