简体   繁体   中英

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

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.

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);
}

No, this is not safe, because the compiler is free to insert padding between or after the two float s in the structure, and so the float s 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!");

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM