Samaursa
Samaursa

Reputation: 17271

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.

Upvotes: 7

Views: 337

Answers (3)

Evgeny Panasyuk
Evgeny Panasyuk

Reputation: 9199

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

Upvotes: 5

Seth Carnegie
Seth Carnegie

Reputation: 75150

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!");

Upvotes: 3

Oswald
Oswald

Reputation: 31685

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.

Upvotes: -1

Related Questions