这个问题不是关于未对齐数据访问的定义,而是为什么memcpy
尽管生成了相同的汇编代码,但类型转换却没有。
我有一些示例代码来解析一个协议,该协议发送一个字节数组,分割成六个字节的组。
void f(u8 *ba) {
// I know this array's length is a multiple of 6
u8 *p = ba;
u32 a = *(u32 *)p;
printf("a = %d\n", a);
p += 4;
u16 b = *(u16 *)p;
printf("b = %d\n", b);
p += 2;
a = *(u32 *)p;
printf("a = %d\n", a);
p += 4;
b = *(u16 *)p;
printf("b = %d\n", b);
}
在将指针增加 6 并进行另一次 32 位读取后,UBSan 报告有关未对齐负载的错误。我使用而不是类型双关来抑制此错误memcpy
,但我不太了解原因。需要明确的是,这是没有 UBSan 错误的相同例程,
void f(u8 *ba) {
// I know this array's length is a multiple of 6 (
u8 *p = ba;
u32 a;
memcpy(&a, p, 4);
printf("a = %d\n", a);
p += 4;
memcpy(&b, p, 2);
printf("b = %d\n", b);
p += 2;
memcpy(&a, p, 4);
printf("a = %d\n", a);
p += 4;
memcpy(&b, p, 2);
printf("b = %d\n", b);
}
两个例程都编译为相同的汇编代码(movl
用于 32 位读取和movzwl
16 位读取),那么为什么一个未定义的行为是另一个未定义的行为呢?是否memcpy
有一些特殊的属性可以保证某些东西?
我不想在memcpy
这里使用,因为我不能依赖编译器在优化它方面做得足够好。