Can I cast an array of POD which has floats to float*?

一曲冷凌霜 提交于 2019-12-08 19:12:05

问题


Consider the following:

#include <vector>
using namespace std;

struct Vec2
{
  float m_x;
  float m_y;
};

vector<Vec2> myArray;

int main()
{
  myArray.resize(100);

  for (int i = 0; i < 100; ++i)
  {
    myArray[i].m_x = (float)(i);
    myArray[i].m_y = (float)(i);
  }

  float* raw;
  raw = reinterpret_cast<float*>(&(myArray[0]));
}

Is raw guaranteed to have 200 contiguous floats with the correct values? That is, does the standard guarantee this?

EDIT: If the above is guaranteed, and if Vec2 has some functions (non-virtual) and a constructor, is the guarantee still there?

NOTE: I realize this is dangerous, in my particular case I have no choice as I am working with a 3rd party library.


回答1:


I realize this is dangerous, in my particular case I have no choice as I am working with a 3rd party library.

You may add compile time check of structure size:

live demo

struct Vec2
{
    float a;
    float b;
};

int main()
{
        int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ];
}

It would increase your confidence of your approach (which is still unsafe due to reinterpret_cast, as mentioned).


raw = reinterpret_cast(&(myArray[0]));

ISO C++98 9.2/17:

A pointer to a POD struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note ]


And finally, runtime check of corresponding addresses would make such solution rather safe. It can be done during unit-tests or even at every start of program (on small test array).

Putting it all together:

live demo

#include <vector>
#include <cassert>
using namespace std;
struct Vec2
{
    float a;
    float b;
};

int main()
{
    int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ];
    typedef vector<Vec2> Vector;
    Vector v(32);
    float *first=static_cast<float*>(static_cast<void*>(&v[0]));
    for(Vector::size_type i,size=v.size();i!=size;++i)
    {
        assert((first+i*2) == (&(v[i].a)));
        assert((first+i*2+1) == (&(v[i].b)));
    }
    assert(false != false);
}



回答2:


No, this is not safe, because the compiler is free to insert padding between or after the two floats in the structure, and so the floats of the structure may not be contiguous.

If you still want to try it, you can add compile time checks to add more surety that it will work:

static_assert(sizeof(Vec2) == sizeof(float) * 2, "Vec2 struct is too big!");
static_assert(offsetof(Vec2, b) == sizeof(float), "Vec2::b at the wrong offset!");



回答3:


The only guarantee that a reinterpret_cast gives is, that you get the original object when you reinterpret_cast the casted object back to the original data type.

Especially, raw is not guaranteed to have 200 contiguous floats with the correct values.



来源:https://stackoverflow.com/questions/13223389/can-i-cast-an-array-of-pod-which-has-floats-to-float

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!