the difference memory size of struct between linux and windows

Mar 19, 2016 at 4:05am
I code a struct on window and linux, but i got the different sizeof() and memory address, could any one tell the reason?

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "stdio.h"
struct A	{ double d; };
struct B : public A	{ short s; };
struct C : public B	{ char c; };

int main()
{
#define p_addr(var) printf("%-6s: %4u: %llu \n", #var, sizeof(var), &var)
	C c;
	printf("struct C: sizeof(c) = %u \n", sizeof(c));
	p_addr(c.d);
	p_addr(c.s);
	p_addr(c.c);

	char ch;
#ifdef __linux__
	scanf("%c", &ch);
#else
	scanf_s("%c", &ch);
#endif

	return 0;
}


On windows(windows 7, 64bit) platform, use vs2013, build an empty project and add the code, here is the result:
struct C: sizeof(c) = 24
c.d   :    8: 2751184
c.s   :    2: 2751192
c.c   :    1: 2751200


On linux(centos 7.0, 64 bit) platform, use gcc 4.9.1, the result is:
struct C: sizeof(c) = 16
c.d   :    8: 140732148814032
c.s   :    2: 140732148814040
c.c   :    1: 140732148814042


Both on windows and linux, all setting use default;
My question is why the struct size are different.

If we set structure-packing:
#pragma pack (4)

the result on windows:
struct C: sizeof(c) = 16
c.d   :    8: 4585632
c.s   :    2: 4585640
c.c   :    1: 4585644


and on linux:
struct C: sizeof(c) = 12
c.d   :    8: 140725878798832
c.s   :    2: 140725878798840
c.c   :    1: 140725878798842

The results are still different;

Last edited on Mar 19, 2016 at 6:09am
Mar 19, 2016 at 11:02am
Basically, because the compiler has some choices to make and clearly they've made different choices. Gaps get left inside structs so that accessing the members is more convenient (i.e faster) depending on the processor.

As you can see, on windows (first example) every member has been given eight bytes to itself, but on the Linux the short and the char are sharing eight bytes between them. I would expect the processor to fetch eight bytes at a time, so there's no performance loss here (in fact, it might even be a performance improvement; when you fetch the short, you're also fetching the char, so if you need the short and the char in quick succession, you've saved yourself an extra fetch there).

You might be interested in having a closer look inside with Clang: http://eli.thegreenplace.net/2012/12/17/dumping-a-c-objects-memory-layout-with-clang/


In the second case, where you have specifically requested packing on a 4 byte boundary, you can see that the windows has done what you asked; 8 bytes for the double, 4 bytes for the short, 4 bytes for the char. The Linux does the same, but continues to have the char and the short share a (4 byte) space. It's the same approach as previously, done in 4 byte lumps.

Basically, the answer is because the Linux compiler here makes the short and the char share a lump of memory (be it 8 bytes or 4), and the Windows compiler makes a different choice and gives them separate lumps of memory.

Last edited on Mar 19, 2016 at 11:03am
Mar 21, 2016 at 12:37am
But I rewrite the struct C like this:
1
2
3
4
5
6
struct C
{
	double d;
	short s;
	char c;
};


The results on Windows and Linux are same, and same with the result on Linux above, either using "#pragma pack (4)" or not;

It means that Window make the different memory-layout with inheritance, how could I make them same ? or does have some topics or manual for me to understand the inherited struct's memory-layout rules on Window and Linux?
Mar 21, 2016 at 1:51am
I found something newly, and create a new topic:
http://www.cplusplus.com/forum/general/187170/ ;
please have a look at if you interested in this problem;
Topic archived. No new replies allowed.