5

Suppose I have a struct, be it union'd or otherwise:

    typedef struct {
        union {
            struct { float x, y, z; } xyz;
            struct { float r, g, b; } rgb;
            float xyz[3];
        } notAnonymous;
    } Vector3;

I've heard that some compilers automatically pad structs to enhance performance by creating word-aligned boundaries.

Presumably such synergy means the size of a struct cannot be guaranteed to be the sum of its component field sizes, and therefore there is a change of data corruption and/or overflow for array xyzs in the following:

inline Vector3 v3Make(float x, float y, float z) { Vector3 v = {x,y,z}; return v; }
float xyzs[6];
*(Vector3*)&xyzs[3] = v3Make(4.0f,5.0f,6.0f);
*(Vector3*)&xyzs[0] = v3Make(1.0f,2.0f,3.0f);

Correct?

timrau
  • 22,578
  • 4
  • 51
  • 64
KomodoDave
  • 7,239
  • 10
  • 60
  • 92

4 Answers4

3

It's true the compiler can lay our your structure with what ever kind of padding it wants. You can use #pragma pack or __attribute__((packed)) to avoid padding on most compilers. In practice, you have three 32-bit fields in there, so it's probably not going to be a problem. You can check by using sizeof on your structure type or a variable of that type and seeing what comes out.

What is a problem is that you're trying to assign a Vector3 to a float variable in your last two lines. That's not going to be allowed. You could hack in what you're trying to do:

*(Vector3 *)&xyzs[3] = v3Make(4.0f, 5.0f, 6.0f);

But that's pretty ugly looking, not to mention confusing. It would be a lot better to change xyzs to being an array of Vector3 rather than of just float.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Regarding, `__attribute((packed))`, see http://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe – Keith Thompson Jan 11 '12 at 22:55
  • Agreed - don't forget to play safe! – Carl Norum Jan 11 '12 at 22:56
  • Silly me - yes of course I need the cast, I've changed my code to reflect what you've said. The confusing nature doesn't affect my question, and a lot of GL code can appear confusing, it's more about functionality than aesthetics imo. Also a good point about the 32-bit fields in my example - I should have gone for something more misshapen. Marking as chosen answer for the accuracy of your comments and the practical relevance of #pragma hint. Many thanks! – KomodoDave Jan 11 '12 at 23:16
2

See answers to the questions in C Defect Report #074

http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_074.html

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Due to the highly technical nature of the linked document I've up voted this post but not chosen it as my preferred answer. – KomodoDave Jan 11 '12 at 23:19
0

It's not inherently unsafe, the compiler/linker takes care of all the offsets.

Unless...you pass the struct to another program written in another language or on another system or to another program written in the same language on the same system but with different compiler settings. Then the offsets may not be calculated correctly.

Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
0

Per the C standard this is at least implementation-defined (dependent on padding issues) and perhaps undefined behavior (due to aliasing rules?), but on all real-world compilers it will work as expected. The alignment of a type can never be larger than its size (it always divides the size of the type evenly) and only a pathologically bad compiler would insert additional padding in structs beyond what's needed to pad each member to the correct alignment for its type.

With that said, in my book at least, this kind of hack is a gratuitous invocation of undefined behavior for the sake of syntactic vinegar and is not acceptable. If there's ever a chance you want to access data in array style, simply always use the array form. It's much less confusing to remember that the vector components are always v[0], v[1], and v[2] than to remember that v[1] and rgb.g might refer to the same object in memory...

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711