【问题标题】:Why do I get a warning for an unaligned pointer but not a reference为什么我收到未对齐指针的警告但没有引用
【发布时间】:2013-06-13 08:44:07
【问题描述】:

我有一个项目要从 32 位 Windows 移植到 64 位,其中包括可以简化如下的代码:

void FuncA(double &x)
{
    x = 0;
}

void FuncB(double *x)
{
   *x = 0;
}

#pack(1)

struct 
{
   char c;
   double x;
} MyStruct;

#pack();

void MyFunc()
{
   MyStruct M;
   FuncA(M.x);  // This is OK
   FuncB(&M.x); // This generates a warning C4366
}

在针对 64 位的 VS2010 SP1 下编译时,使用打包结构的成员调用 FuncB 会生成以下警告:

警告 C4366:一元“&”运算符的结果可能未对齐

而调用FuncA 不会。我原以为这两种情况都会编译成几乎相同的代码。引用在对齐问题上是否比等效指针更安全?还是 MSVC 根本没有在应该发出警告的地方发出警告?该项目需要维护结构打包,所以我的选择是将FuncB更改为

void FuncB(__unaligned double *x)
{
   *x = 0;
}

或在所有此类情况下简单地使用FuncA。后者更可取,因为它更便携,但我想知道它是否会起作用,或者在参考案例中缺少警告仅仅是编译器中的一个缺点?

编辑:此错误的 Microsoft 帮助条目是 here__unaligned 帮助表明不注意此警告将导致在 Itanium 处理器上引发异常。进一步搜索 MSDN 建议 there may be issues surrounding unaligned references。虽然这可能不会对我当前的用户造成问题,但如果 Itanium 架构在未来得到更广泛的使用,我可能会设置支持噩梦。现在计划为所有使用打包结构的函数添加特定的包装器,以避免指针和 __unaligned 关键字。

【问题讨论】:

标签: c++ 32bit-64bit memory-alignment


【解决方案1】:

引用和指针几乎是一回事(可以这么说),所以从安全角度来看,它没有什么不同。这可能更多是一种疏忽和/或编译器不太关心引用,因为它们不能在 C++ 环境之外传递(尽管我倾向于认为这只是一种疏忽)。

也可能是编译器更关心指针,因为指针更有可能用于性能,您希望在 double 值的范围内迭代(例如,通过分配比结构本身更多的空间使用,并在其后存储更多 double 值) - 你不能通过引用来做到这一点。由于未对齐访问至少比对齐访问慢,这可能会对性能产生影响,并且在某些系统中,它会导致操作系统陷阱,这将“修复”未对齐访问(以几个订单的速度比普通的对齐访问慢),或者操作系统只是说“您的程序导致了未对齐的访问,我正在杀死它”。

多线程也存在问题,因为未对齐的访问可能不会自动更新数据。当然,对于线程之间共享的数据,您应该使用std::atomic 或类似名称。

x86 完全能够从未对齐的地址读取double。我认为 Itanium 不是,但我怀疑您无论如何都不会使用该处理器,从统计上讲。其他较旧的架构(例如 Alpha)可能无法读取未对齐的内存。

【讨论】:

  • 未对齐访问比对齐访问慢,并且在多线程环境中它可能会产生其他不良影响(intel 中的对齐读/写是原子的,但未对齐访问并非如此:使用两个线程将值 1 和 2^31 写入同一个变量和读取该值的线程,如果该值对齐,则保证读取 1 或 2^31;未对齐访问不是这种情况)。其他平台 (SPARC) 无法处理未对齐的读取/写入,处理器将陷入陷阱。
  • 我更新了“这就是为什么我认为指针比引用更重要”,以解释未对齐的访问速度较慢。我不知道 SPARC 有任何版本的 Windows,所以我认为它的行为并不重要,而且 64 位 ARM 也不适用于 Windows。剩下 X86 和 Itanium...
  • 这只是关于 C++ 编译器警告和未对齐访问的评论,但如果您想考虑 alpha 而不是 sparc。有多个 Windows 操作系统在 alpha 中运行,不确定新版本是否可以。关于编辑……哎哟。以前的答案更好!
  • 我倾向于同意这是一个疏忽/编译器的缺陷,但是如果没有一个 Itanium windows box 来测试它,这是一个很难证明的问题。 MSDN 链接表明未对齐的引用是一个潜在问题,因此我将使用扩展为 __unaligned 的宏来运行 Itanium 版本,但也可以在不需要的地方轻松删除。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
相关资源
最近更新 更多