位字段结构的C++严格别名规则

Ale*_*Pai 6 c++ strict-aliasing bit-fields

下面的getValue()成员函数是否违反了c ++严格别名规则?

根据标准,我认为setValue()违反了严格的别名规则,因为double既不是聚合类型也不是IEEE754_64的基类.

getValue()怎么样?当数据成员是位字段形式时,它是一个未定义的行为,如下例所示?

我在一个大型项目中使用类似的代码.GCC -O2和-O3输出错误的值.如果我添加-fno-strict-aliasing,问题就消失了.此外,如果我使用memcpy而不是在getValue()中进行转换,问题就消失了.不确定它是否是GCC错误.

#include <iostream>
#include <cstring>

using namespace std;
struct IEEE754_64
{
  void setValue(double);
  unsigned long long getValue();
  // Data members
  unsigned long long d_mantissa : 52;
  long long d_exponent : 11;
  unsigned long long d_sign : 1;
};

void IEEE754_64::setValue(double d)
{
  (*this) = *reinterpret_cast<IEEE754_64*>(&d);
}

unsigned long long IEEE754_64::getValue()
{
  return * reinterpret_cast<unsigned long long *>(this);
}

int main()
{
  double b = 1.0;
  IEEE754_64 d;

  memcpy(&d, &b, sizeof(double));
  cout<<hex<<d.getValue()<<endl;

  d.setValue(1.0);
  cout<<hex<<d.getValue()<<endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

M.M*_*M.M 4

的行为reinterpret_cast<T *>(&a)取决于实际位于 的内存位置的对象a

非正式地,如果那里实际上T也有一个对象(当然,只有当它T是 的子对象时才会发生a,反之亦然),那么转换的结果是指向该T对象的指针。

否则,强制转换的结果是指向a错误类型的指针,并且读取它可能会违反严格的别名规则。

正式地,上述内容在标准的 [expr.static.cast]/13 和 [basic.compound]/4 部分中进行了解释,请参阅此处了解详细信息。


考虑到这一点,通过类型的左值setValue读取 a ,毫无疑问这是严格的别名违规。doubleIEEE754_64

对于这种getValue情况,我们必须了解其行为reinterpret_cast<unsigned long long *>(this)不太直接。

根据 [basic.compound]/4,对象及其第一个非静态数据成员始终是指针可相互转换的。它没有列出位域的任何例外。

但 [expr.static.cast]/13 的相关文本是:

否则,如果原始指针值指向对象a,并且存在可与 进行指针相互转换的b类型(忽略 cv 限定)的对象,则结果是指向 的指针。Tab

如果我们接受位域是“类型的对象unsigned long long”,那么转换的结果就是指向位域的指针。然而,该标准没有定义指向位域的指针的行为。

因此,恕我直言,解释上述文本的最佳方法是说位域不是类型的对象unsigned long long。我相信这与标准的其余部分是一致的;尽管没有位域类型的纯右值,但它确实讨论了位域类型的左值。

加起来; 我相信 的结果reinterpret_cast<unsigned long long *>(this)不是指向 的指针this->d_mantissa,因此该函数使用类型 的泛左值getValue()访问类型的对象,违反了严格的别名规则。IEEE754_64unsigned long long

  • 只是指出该标准没有定义位域的实际布局。即使别名本身是允许的,并且已知“double”具有 IEEE754 布局,仍然无法保证位字段映射到正确的位。另外,您应该指出,与许多其他情况一样,“memcpy”可用于消除严格的别名冲突(编译器通常足够聪明,不会实际复制数据)。基本上,“memcpy”被视为通过指向 cv 限定的“char”的指针进行(允许的)访问。 (2认同)