首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我应该担心指针转换过程中的对齐问题吗?

我应该担心指针转换过程中的对齐问题吗?
EN

Stack Overflow用户
提问于 2012-12-14 23:21:49
回答 7查看 16.6K关注 0票数 55

在我的项目中,我们有这样一段代码:

代码语言:javascript
复制
// 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*。但是技术负责人说这没问题,大多数编译器在强制转换后仍然保持相同的指针值,我可以像这样写代码。

坦率地说,我并不是很信服。经过研究,我发现有些人反对使用像上面这样的指针类型转换,例如herehere

所以我的问题是:

在实际项目中强制转换后取消引用指针真的安全吗?reinterpret_cast

  • Is

  • 在C风格的强制转换和C++之间有什么不同吗?
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-12-14 23:28:55

  1. Is在实际的project?

类型转换后解除对指针的引用是非常安全的

如果指针碰巧没有正确对齐,它确实会导致问题。我亲眼看到并修复了实际生产代码中的总线错误,这些错误是由将char*强制转换为更严格对齐的类型造成的。即使你没有得到一个明显的错误,你也可能会有一些不太明显的问题,比如性能变慢。严格遵循标准以避免UB是一个好主意,即使您不会立即看到任何问题。(代码违反的一个规则是严格的别名规则,§3.10/10*)

一个更好的选择是在缓冲区重叠的情况下使用std::memcpy()std::memmove (或者更好的bit_cast<>())

代码语言:javascript
复制
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数组比必要的更严格地对齐,因为程序员经常会弄错。

代码语言:javascript
复制
#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

  1. Is C风格的类型转换和reinterpret_cast?

有什么不同

那得看情况。C风格的强制转换根据所涉及的类型做不同的事情。指针类型之间的C风格转换将导致与reinterpret_cast相同的结果;参见§5.4显式类型转换(强制转换表示法)和§5.2.9-11。

  1. Is C和C++?

之间有什么区别吗?

只要您处理的类型在C中是合法的,就不应该有这样的问题。

*另一个问题是,C++没有指定从一个指针类型转换为具有更严格对齐要求的类型的结果。这是为了支持那些不能表示未对齐指针的平台。然而,今天的典型平台可以表示未对齐的指针,而编译器指定这样的强制转换的结果正如您所期望的那样。因此,与别名冲突相比,此问题是次要的。参见expr.reprepret.cast/7。

票数 40
EN

Stack Overflow用户

发布于 2012-12-14 23:30:46

这并不好,真的。对齐可能是错误的,代码可能会违反严格的别名。您应该显式地解压它。

代码语言:javascript
复制
i1 = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;

等等。这绝对是定义良好的行为,而且作为额外的好处,它也是独立于字符顺序的,不像你的指针类型转换。

票数 27
EN

Stack Overflow用户

发布于 2012-12-14 23:34:05

在这里的示例中,如果初始字符指针正确对齐,那么您所做的操作在几乎所有现代CPU上都是安全的。一般来说,这是不安全的,也不能保证正常工作。

如果初始字符指针未正确对齐,这将在x86和x86_64上工作,但在其他体系结构上可能会失败。如果你幸运的话,它只会让你崩溃,你就会修复你的代码。如果你不走运,未对齐的访问将被你操作系统中的陷阱处理程序修复,如果没有任何明显的反馈来解释为什么它如此缓慢,你将会有糟糕的性能(我们谈论的是对于某些代码来说冰川般的缓慢,这在20年前的alpha上是一个大问题)。

即使是在x86 & co上,未对齐的访问速度也会更慢。

如果你想在现在和将来都是安全的,只需要memcpy,而不是像这样做任务。一个现代的编译器可能会对memcpy进行优化,并做正确的事情,如果没有,memcpy本身就会有对齐检测,并且会做最快的事情。

此外,您的示例在一点上是错误的: sizeof(int)并不总是4。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13881487

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档