将double数组转换为双精度结构

时间:2015-06-26 21:26:18

标签: c++ arrays struct language-lawyer static-cast

将双数组转换为由双精度构成的结构是否可以?

struct A
{
   double x;
   double y;
   double z;
};

int main (int argc , char ** argv)
{
   double arr[3] = {1.0,2.0,3.0};
   A* a = static_cast<A*>(static_cast<void*>(arr));
   std::cout << a->x << " " << a->y << " " << a->z << "\n";
}

这会打印1 2 3。但它是否保证每次都可以与任何编译器一起工作?

编辑:根据

  

9.2.21:指向标准布局结构对象的指针,适当转换?使用reinterpret_cast,指向其初始成员(...),反之亦然。

如果我用

替换我的代码
struct A
{
  double & x() { return data[0]; }
  double & y() { return data[1]; }
  double & z() { return data[2]; }
private:
   double data[3];
};

int main (int, char **)
{
   double arr[3] = {1.0,2.0,3.0};
   A* a = reinterpret_cast<A*>(arr);
   std::cout << a->x() << " " << a->y() << " " << a->z() << "\n";
}

然后它保证工作。正确?我知道很多人都不会觉得这很令人满意,但是使用结构体并且不必复制输入数组数据是有好处的。我可以在该结构中定义成员函数来计算标量和向量积,距离等,这将使我的代码比使用数组更容易理解。

怎么样

int main (int, char **)
{
   double arr[6] = {1.0,2.0,3.0,4.0,5.0,6.0};
   A* a = reinterpret_cast<A*>(arr);
   std::cout << a[0].x() << " " << a[0].y() << " " << a[0].z() << "\n";
   std::cout << a[1].x() << " " << a[1].y() << " " << a[1].z() << "\n";
}

这是否也可以保证工作,或者编译器可以在数据成员之后放置一些内容,以便sizeof(A) > 3*sizeof(double)?是否有任何可移植的方法来阻止编译器这样做?

6 个答案:

答案 0 :(得分:9)

不,这不能保证。

唯一禁止任何编译器在xy之间或yz之间插入填充的内容是常识。任何语言标准都没有规定不允许它。

即使没有填充,即使A的表示与double[3]的表示完全相同,它仍然无效。该语言不允许您假装一种类型是另一种类型。您甚至不允许将struct A { int i; };的实例视为struct B { int i; };

答案 1 :(得分:2)

该标准几乎不保证对象的内存布局。

对于类/结构:

  

9.2./15:分配具有相同访问控制的类的非静态数据成员,以便以后的成员具有更高的地址   在一个类对象中。非静态数据的分配顺序   具有不同访问控制的成员未指定。履行   对齐要求可能导致两个相邻成员不能立即分配;可能要求   用于管理虚拟功能和虚拟基类的空间。

对于数组,元素是连续的。关于对齐没有任何说法,所以它可能使用或不使用相同的对齐规则而不是结构:

  

8.3.4:数组类型的对象包含一个连续分配的非空N个子类型的T类型。

在特定示例中,您唯一可以确定的是a.x对应于arr[0],如果使用reinterpret_cast:

  

9.2.21:指向标准布局结构对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员(...)   反之亦然。 [
  &GT;

答案 2 :(得分:1)

不能保证,即使它应该与我在常见架构上知道的所有编译器一起工作,因为C语言规范说:

6.2.6类型的表示 6.2.6.1 General1除了本子条款中所述之外,所有类型的表示都是未指定的。并且它在结构中的默认填充上没有说明。

当然,常见架构最多使用64位,这些架构的大小为双倍,因此应该没有填充,并且您的转换应该有效。

但是要注意:你明确地调用未定义的行为,下一代编译器在编译这样的演员时可以做任何

答案 3 :(得分:0)

据我所知,答案是:是的。

唯一能让你失望的是#pragma指令,它为struct提供了一些非常不寻常的对齐设置。例如,如果double在您的机器上占用8个字节,并且#pragma指令告诉您将16个字节边界上的每个成员对齐,这可能会导致问题。除此之外,你没事。

答案 4 :(得分:0)

std :: complex实现msvc使用数组解决方案,而llvm libc ++使用前一种形式。

我认为,只需检查libc ++的std :: complex的实现,并使用相同的解决方案。

答案 5 :(得分:-3)

我不同意这里的共识。其中包含三个双精度的结构与其中包含3个双精度的数组完全相同。除非你专门打包结构,并且是在一个奇怪的处理器上,它具有奇数个字节用于双精度。

它没有内置于语言中,但我会感到安全。风格明智我不会这样做,因为它只是令人困惑。