在我的项目中,我们有这样一段代码:
// 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));我和我的技术负责人谈过,这段代码可能无法移植,因为它试图将一个unsigned char*转换为一个通常有更严格对齐要求的int*。但是技术负责人说这没问题,大多数编译器在强制转换后仍然保持相同的指针值,我可以像这样写代码。
坦率地说,我并不是很信服。经过研究,我发现有些人反对使用像上面这样的指针类型转换,例如here和here。
所以我的问题是:
在实际项目中强制转换后取消引用指针真的安全吗?reinterpret_cast
发布于 2012-12-14 23:28:55
类型转换后解除对指针的引用是非常安全的
如果指针碰巧没有正确对齐,它确实会导致问题。我亲眼看到并修复了实际生产代码中的总线错误,这些错误是由将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));一些编译器比其他编译器更努力地确保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();
}http://ideone.com/FFWCjf
有什么不同
那得看情况。C风格的强制转换根据所涉及的类型做不同的事情。指针类型之间的C风格转换将导致与reinterpret_cast相同的结果;参见§5.4显式类型转换(强制转换表示法)和§5.2.9-11。
之间有什么区别吗?
只要您处理的类型在C中是合法的,就不应该有这样的问题。
*另一个问题是,C++没有指定从一个指针类型转换为具有更严格对齐要求的类型的结果。这是为了支持那些不能表示未对齐指针的平台。然而,今天的典型平台可以表示未对齐的指针,而编译器指定这样的强制转换的结果正如您所期望的那样。因此,与别名冲突相比,此问题是次要的。参见expr.reprepret.cast/7。
发布于 2012-12-14 23:30:46
这并不好,真的。对齐可能是错误的,代码可能会违反严格的别名。您应该显式地解压它。
i1 = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;等等。这绝对是定义良好的行为,而且作为额外的好处,它也是独立于字符顺序的,不像你的指针类型转换。
发布于 2012-12-14 23:34:05
在这里的示例中,如果初始字符指针正确对齐,那么您所做的操作在几乎所有现代CPU上都是安全的。一般来说,这是不安全的,也不能保证正常工作。
如果初始字符指针未正确对齐,这将在x86和x86_64上工作,但在其他体系结构上可能会失败。如果你幸运的话,它只会让你崩溃,你就会修复你的代码。如果你不走运,未对齐的访问将被你操作系统中的陷阱处理程序修复,如果没有任何明显的反馈来解释为什么它如此缓慢,你将会有糟糕的性能(我们谈论的是对于某些代码来说冰川般的缓慢,这在20年前的alpha上是一个大问题)。
即使是在x86 & co上,未对齐的访问速度也会更慢。
如果你想在现在和将来都是安全的,只需要memcpy,而不是像这样做任务。一个现代的编译器可能会对memcpy进行优化,并做正确的事情,如果没有,memcpy本身就会有对齐检测,并且会做最快的事情。
此外,您的示例在一点上是错误的: sizeof(int)并不总是4。
https://stackoverflow.com/questions/13881487
复制相似问题