是否违反严格的别名规则,使用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。我的问题集中在这样做是否违反了严格的别名。
答案 0 :(得分:4)
第一个循环 在技术上违反严格别名 - 它通过uint32_t
类型的左值访问char *
个对象。但是,很难看出任何优化器在这种特定情况下会如何导致问题。如果你改变了一点,那么你就是这样做的:
printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);
你可能看到两次打印的相同字符串 - 因为优化器只能将buffer_cc[0]
加载到寄存器中一次,因为第二行只修改了一个对象输入uint32_t
。
第二个循环,memcpy
他们回来了,很好。
答案 1 :(得分:1)
buffer_cc[0]
和strings[3]
(例如)是引用相同内存位置但属于同一类型的指针,因此不会违反严格别名。 buffer[0]
不是指针,因此不会违反严格的别名。在解除引用指针时出现别名优化,所以我不希望这会导致问题。
正如您在代码和问题的最后一段中所提到的那样,当指针和uint32_t具有不同的大小时,示例代码中的实际问题就出现了。
此外,您始终可以为char*
设置别名以指向其他类型而不违反严格别名,但反之亦然。