15

Can a C++ compiler (specifically g++) re-order the internal elements of a struct?

I'm seeing some strange behaviour where I have a structure that contains something like the following:

Struct SomeStruct{
   ...
   ...
   long someLong;
   long someLongArray[25];
   unsigned long someUnsignedLong;
   unsigned long someUnsignedLongArray[8];
   unsigned long int someUnsignedLongInt;
   ...
   ...
};

When I write output this to file, the order of someUnsignedLongArray and someLongArray seem to be reversed (i.e. the elements in someLongArray[] appear after someUnsignedLong and the elements of someUnsignedLongArray[] appear after someLong). Is this possible??

Thanks


Update: As requested, I am writing out the structure using the following:

int fd = open(fspec,O_RDWR|O_CREAT|O_TRUNC,0666);
int writeRes =  write(fd,(char *)&someStruct,sizeof(SomeStruct));

For completeness, here is the full struct:

struct SomeStruct{
byte someByte;
byte someByteArray[6];
char someChar;
char someCharArray[5];
char someCharArrayArray[3][5];
short someShort;
signed short someShortArray[2];
unsigned short someUnsignedShort;
unsigned short someUnsignedShortArray[8];
int someInt;
int someIntArray[3];
int someIntArrayArrayArrayArray[4][3][2][6];
int *pSomeInt;
unsigned int someUnsignedInt;
unsigned int someUnsignedIntArray[9];
long someLong;
long someLongArray[25];
unsigned long someUnsignedLong;
unsigned long someUnsignedLongArray[8];
unsigned long int someUnsignedLongInt;
long long someLongLong;
long long someLongLongArray[5];
bool someBool;
bool someBoolArray[3];
unsigned long long someUnsignedLongLong;
unsigned long long someUnsignedLongLongArray[5];
unsigned long long someUnsignedLongLongArrayArray[5][2];
unsigned long long int *pSomeUnsignedLongLongInt;
};
Lehane
  • 47,588
  • 14
  • 53
  • 53
  • How do you write the struct to a file? – tstenner May 27 '09 at 16:18
  • Are you certain that you are seeing what you think you are seeing? ie have you written unique bit patterns into each element and can trace them to the file? Also what #pragma pack (if any) are you using around the struct? – Peter M May 27 '09 at 16:29
  • Perhaps he's writing the bytes of the struct, instead of the elements of the struct, to the file. – isekaijin May 27 '09 at 16:31
  • Can you replace the "..." and write a main function that exhibits the issue? It makes a difference what else is in the struct, and how you're writing it to file. Did you cast a SomeStruct* to char* and write sizeof(SomeStruct) bytes, or something else? – Steve Jessop May 27 '09 at 16:41
  • Btw: you can check the order of the fields with offsetof, without writing anything to disk. – Steve Jessop May 27 '09 at 16:47
  • And you run this code on an x86 CPU? Taking endianess in consideration it's generally better to write each element of a struct at a time (using appropriate hton()-macros) if you want your code to be portable. – Andreas Magnusson May 27 '09 at 21:17

2 Answers2

35

It normally can't reorder elements, no.

An exception is if there's an access specifier separating them:

struct Foo {    
  A a;
  B b;
  C c;
private:
  D d;
  E e;
  F f;
};

a, b and c are guaranteed to be stored in this order, and d, e and f are guaranteed to be stored in order. But there is no guarantees about where a, b and c are stored relative to d, e and f.

Another thing to keep in mind is that the compiler can insert as much padding as it likes, even if it doesn't reorder anything.

Here's the relevant part of the standard:

Section 9.2.12:

Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1)"

JFMR
  • 23,265
  • 4
  • 52
  • 76
jalf
  • 243,077
  • 51
  • 345
  • 550
  • just curious if you have a citation for this? I'm not saying you're wrong, but it would be useful to have a citation. – Doug T. May 27 '09 at 16:25
  • I think it's only PODs which can't be reordered within access-specifier blocks. Non-PODs have no order requirements at all. But since you're looking it up anyway for Doug T, and my copy is all the way upstairs, I'll let you check ;-) – Steve Jessop May 27 '09 at 16:37
  • oof, guess I'd better look it up then... ;) 9.2.12 says "Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1)." @onebyone: Interestingly, it doesn't seem to say anything about POD vs non-POD. If you're sure about it, I'll let you look that one up. ;) – jalf May 27 '09 at 16:53
  • I'm not sure - for some reason I thought the stuff about order was in the POD section, but evidently not. – Steve Jessop May 27 '09 at 18:43
8

It can't, see Automated field re-ordering in C structs to avoid padding and Why doesn't GCC optimize structs? for further information.

I don't know what you mean with "reversed", perhaps you should add some code and the output.

Community
  • 1
  • 1
tstenner
  • 10,080
  • 10
  • 57
  • 92
  • When I say reversed, I mean that the elements in someUnsignedLongArray[] appear directly after someLong. I'll clarify the question. – Lehane May 27 '09 at 16:16
  • It's not because it's not allowed to but because it's complex and breaks many things. GCC was able to do that and research on it is still being done. See [Is there a GCC keyword to allow structure-reordering?](https://stackoverflow.com/q/14671253/995714) – phuclv Sep 04 '19 at 01:07