问题描述
使用uint32_t移动任何类型的项目然后将其读回是否违反严格的别名规则?如果是这样,是否也违反了严格的别名规则,即从uint32_ts数组到任何类型的数组进行memcpy,然后再读回元素?
Does it violate strict aliasing rules to move items of any type around using uint32_t, then read them back? If so, does it also violate strict aliasing rules to memcpy from an array of uint32_ts to an array of any type, then read the elements back?
以下代码示例演示了两种情况:
The following code sample demonstrates both cases:
#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.我的问题集中在这样做是否违反严格的别名.
Please disregard my assumption of a 32-bit platform. Also, if the elements aren't the same size as uint32_t, I know to pad them and copy the correct number of uint32_t's. My question focuses on whether or not doing so violates strict aliasing.
推荐答案
第一个循环确实违反了严格的别名-它通过类型为char *
的左值访问uint32_t
对象.但是,在这种特定情况下,很难看到任何优化器都会给您带来问题.如果您对其进行了一些更改,则您将执行以下操作:
The first loop does technically violate strict aliasing - it accesses uint32_t
objects through an lvalue of type char *
. It's hard to see how any optimiser would cause you a problem in this specific case, though. If you altered it a little so you were doing something like:
printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);
您可能看到相同的字符串打印了两次-因为优化器将在其权限内仅将buffer_cc[0]
加载到寄存器一次,因为第二行仅修改了uint32_t
.
You might see the same string printed twice - since the optimiser would be within its rights to only load buffer_cc[0]
into a register once, because the second line is only modifying an object of type uint32_t
.
第二个循环,可以将它们重新返回.
The second loop, that memcpy
s them back, is fine.
这篇关于将一种类型的值与另一种类型的值移动是否违反严格的别名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!