Hi folks,

I have a mathematic Vector3 class that looks like

class Vector3
{
public:
   union
   {
      struct
      {
        float x;
        float y;
        float z;
        // btw, if declared like
        // float x, y, z;
        // will there be a difference in packing order?
      };

      float v[3];
   };

   // insert many member and static functions here
}

I want to use it in another struct like this

struct Vertex
{
   Vector3 p;
   Vector3 n;
   Vector3 c;
}

And then pass it to a function which accesses it sequentially

void work(void* p, void* n, void* c, int stride)
{
   do {
   doP(p); p += stride; // actually i made up this code. I don't know if you can 
   doN(n); n += stride; // increment void pointers like this... but you get the idea.
   doC(C); n += stride;
   } while (not end of sequence)
}

// calling work
Vertex v[1000];
work(&v[0].p, &v[0].n, &v[0].c, sizeof(Vertex));

My question is, with the above code, is it always safe to call assume the packing order is in the manner I call work() ?

How can I make the code safer and "portable" if that is the correct word to use. It will be great if you can point me to easy-to-understand readings on this topic. Perhaps on union/class/struct keyword in relation to this issue.

Recommended Answers

All 3 Replies

If I understand your question correctly, the compiler is not allowed to reorder struct/class members between access specifiers. You can make the order unspecified like so:

struct Vertex
{
   public: Vector3 p;
   public: Vector3 n;
   public: Vector3 c;
}

Here is what I think is a simpler version of the question you are asking.

struct Foo {
    int x, y;
};

Foo bar[2];

void f()
{
    int* p = &bar[0].x;

    // ...
}

I believe you are asking where there is any portable of incrementing p so that it points to bar[1].x instead of pointing to bar[0].x where it currently points.

I believe that the answer to that question is no: There is no portable way of doing this. Probably the closest you can come is something like this:

typedef unsigned char* UCP;

p = reinterpret_cast<int*> ( p +
    (reinterpret_cast<UCP>(&bar[1].x) - reinterpret_cast<UCP>(&bar[0].x)));

The idea is that C++ blesses pointers to unsigned char as if they are pointers to raw memory, and casts to and from that type (which I have abbreviated as UCP) have portability properties that other uses of reinterpret_cast do not share.

So the code above "measures" the distance between corresponding members of adjacent elements of bar in unsigned-char units, then applies that offset to the UCP address of one element to obtain the address of the corresponding other element.

I am going out on a limb here, but my guess is that (a) most members of the C++ committee have not thought about this specific issue, and if asked whether it should be considered portable, there would not be immediate agreement on the answer, but that (b) most compilers would wind up generating code from these statements that would do the kind of thing you want.

If I understand your question correctly

Here is what I think is a simpler version of the question you are asking

sorry for being unclear about what i was asking, but you guys got what I needed. many thanks =) I will try the "distance measuring" and see if the offset turns out to be consistent.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.