Eri*_*c Z 51 c c++ casting alignment
在我的项目中,我们有一段这样的代码:
// raw data consists of 4 ints
unsigned char data[16];
int i1, i2, i3, i4;
i1 = *((int*)data);
i2 = *((int*)(data + 4));
i3 = *((int*)(data + 8));
i4 = *((int*)(data + 12));
Run Code Online (Sandbox Code Playgroud)
我和我的技术负责人谈到这个代码可能不便携,因为它试图将a unsigned char*转换为int*通常具有更严格的对齐要求的代码.但是技术主管说没关系,大多数编译器在转换后仍保持相同的指针值,我可以像这样编写代码.
坦率地说,我并不是真的相信.经过研究,我发现有些人反对使用上面的指针铸件,例如,这里和这里.
所以这是我的问题:
reinterpret_cast?之间有什么区别吗?bam*_*s53 36
1.在真实项目中投射后取消引用指针真的很安全吗?
如果指针碰巧没有正确对齐,它确实会导致问题.我个人已经看到并修复了真实的生产代码中的总线错误,这些错误是由char*一个更严格的对齐类型引起的.即使您没有得到明显的错误,也可能会出现性能下降等不太明显的问题.即使您没有立即发现任何问题,严格遵守标准以避免UB是一个好主意.(并且代码破坏的一条规则是严格的别名规则,§3.10/ 10*)
更好的选择是使用std::memcpy()或std::memmove缓冲区是否重叠(或更好bit_cast<>())
unsigned char data[16];
int i1, i2, i3, i4;
std::memcpy(&i1, data , sizeof(int));
std::memcpy(&i2, data + 4, sizeof(int));
std::memcpy(&i3, data + 8, sizeof(int));
std::memcpy(&i4, data + 12, sizeof(int));
Run Code Online (Sandbox Code Playgroud)
有些编译器比其他编译器工作更努力,以确保char数组的排列比必要的更严格,因为程序员经常会这样做错误.
#include <cstdint>
#include <typeinfo>
#include <iostream>
template<typename T> void check_aligned(void *p) {
std::cout << p << " is " <<
(0==(reinterpret_cast<std::intptr_t>(p) % alignof(T))?"":"NOT ") <<
"aligned for the type " << typeid(T).name() << '\n';
}
void foo1() {
char a;
char b[sizeof (int)];
check_aligned<int>(b); // unaligned in clang
}
struct S {
char a;
char b[sizeof(int)];
};
void foo2() {
S s;
check_aligned<int>(s.b); // unaligned in clang and msvc
}
S s;
void foo3() {
check_aligned<int>(s.b); // unaligned in clang, msvc, and gcc
}
int main() {
foo1();
foo2();
foo3();
}
Run Code Online (Sandbox Code Playgroud)
2. C风格的演员和reinterpret_cast有什么区别吗?
这取决于.C风格的演员表根据所涉及的类型做不同的事情.指针类型之间的C风格转换将产生与reinterpret_cast相同的东西; 参见§5.4 显式类型转换(强制转换符号)和§5.2.9-11.
3. C和C++之间有什么区别吗?
只要您处理C中合法的类型,就不应该存在.
*另一个问题是C++没有指定从一种指针类型转换为具有更严格对齐要求的类型的结果.这是为了支持甚至无法表示未对齐指针的平台.然而,今天典型的平台可以表示未对齐的指针,编译器将这种演员的结果指定为您期望的结果.因此,此问题是别名违规的次要问题.见[expr.reinterpret.cast]/7.
Pup*_*ppy 28
真的,这不太好.对齐可能是错误的,并且代码可能违反严格的别名.你应该明确解压缩它.
i1 = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;
Run Code Online (Sandbox Code Playgroud)
这绝对是明确定义的行为,作为奖励,它也与字节顺序无关,与指针转换不同.
在这个示例中,如果初始字符串指针正确对齐,那么您在这里显示的内容几乎对所有现代CPU都是安全的.一般来说,这是不安全的,不能保证工作.
如果初始char指针未正确对齐,则这将在x86和x86_64上运行,但在其他体系结构上可能会失败.如果你很幸运,它只会让你崩溃,你将修复你的代码.如果你运气不好,你的操作系统中的陷阱处理程序会修复未对齐的访问权限,你会有很糟糕的表现而没有任何关于为什么它如此缓慢的明显反馈(我们说某些代码的速度很慢,这是20年前阿尔法的一个巨大问题).
即使在x86&co上,未对齐访问也会变慢.
如果你想在今天和将来保持安全,memcpy而不是像这样做任务.现代编译器可能会优化memcpy并做正确的事情,如果没有,memcpy它本身将具有对齐检测并将做最快的事情.
此外,您的示例在某一点上是错误的:sizeof(int)并不总是4.
解压缩char缓冲数据的正确方法是使用memcpy:
unsigned char data[4 * sizeof(int)];
int i1, i2, i3, i4;
memcpy(&i1, data, sizeof(int));
memcpy(&i2, data + sizeof(int), sizeof(int));
memcpy(&i3, data + 2 * sizeof(int), sizeof(int));
memcpy(&i4, data + 3 * sizeof(int), sizeof(int));
Run Code Online (Sandbox Code Playgroud)
转换违反了别名,这意味着编译器和优化器可以自由地将源对象视为未初始化的对象。
关于您的3个问题:
reinterpret_cast。