以前在内存对齐方面有一些很好的答案,但是我觉得还没有完全回答一些问题。
例如:
What is data alignment? Why and when should I be worried when typecasting pointers in C?
What is aligned memory allocation?
我有一个示例程序:
#include <iostream>
#include <vector>
#include <cstring>
int32_t cast_1(int offset) {
std::vector<char> x = {1,2,3,4,5};
return reinterpret_cast<int32_t*>(x.data()+offset)[0];
}
int32_t cast_2(int offset) {
std::vector<char> x = {1,2,3,4,5};
int32_t y;
std::memcpy(reinterpret_cast<char*>(&y), x.data() + offset, 4);
return y;
}
int main() {
std::cout << cast_1(1) << std::endl;
std::cout << cast_2(1) << std::endl;
return 0;
}
cast_1
函数输出ubsan对齐错误(如预期),但cast_2
不会。但是,cast_2
对我来说可读性差得多(需要3行)。 cast_1
的意图非常清晰,即使它是UB。
问题:
1)当意图很明确时,为什么cast_1
UB?我了解对齐可能存在性能问题。
2)cast_2
是固定cast_1
UB的正确方法吗?
答案 0 :(得分:3)
1)为什么
cast_1
UB?
因为语言规则这么说。实际上有多个规则。
您访问对象的偏移量不符合int32_t
的对齐要求(对齐要求为1的系统除外)。如果不符合类型的对齐要求,则无法创建任何对象。
char
指针不能别名为int32_t
。
2)
cast_2
是固定cast_1
UB的正确方法吗?
cast_2
具有明确的行为。该函数中的reinterpret_cast
是多余的,并且使用魔术常数(使用sizeof
)是很不好的。
答案 1 :(得分:1)
第一个问题是WRT,对于编译器来说,为您处理这个问题将是微不足道的。要做的就是对程序中的所有其他非字符加载进行模拟。
精确地编写了对齐规则,因此编译器可以生成在许多平台上都能很好地执行代码,在这些平台上,对齐的内存访问是一种快速的本机操作,而对齐错误的访问与memcpy等效。除了可以证明对齐的地方之外,编译器还必须以缓慢且安全的方式处理每次加载。