12

我有一个项目要从 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 帮助条目在此处。__unaligned帮助表明不注意此警告将导致在 Itanium 处理器上引发异常进一步搜索 MSDN 表明可能存在围绕未对齐引用的问题。虽然这可能不会对我当前的用户造成问题,但如果 Itanium 架构在未来得到更广泛的使用,我可能会设置支持噩梦。现在计划为所有使用打包结构的函数添加特定的包装器,以避免指针和 __unaligned 关键字。

4

1 回答 1

9

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

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

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

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

于 2013-06-17T11:54:37.880 回答