1

As subject says, I got different result of the same operation that calculate a same structure. The struct is below.

struct test
{
  char m1;
  double d1;
}

When use sizeof(struct test) calculate it in gcc-4.6.3 and gcc-4.2 in linux, I got the result "12". While I use gcc-4.6.1 in linux and VC 6.0 in WinXP, I got the result "16". So I'm confused, why this happen? How GCC calculate a struct's size?

added:

as the answers say,arm linux require 8-byte alignment for AAPCS defines,but why vc 6.0 in x86 get the result "16"?Does anyone use vc 2003 or later calculate this?

what's more does C standard such as C89/C99 define this?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ezio
  • 1,116
  • 4
  • 13
  • 25
  • Your Linux is 32-bit, but your Windows 64? – Daniel Fischer May 26 '13 at 13:55
  • @Daniel Fischer no,both 32bit,pc is X86,arm is cortex-a9. – Ezio May 26 '13 at 14:02
  • 1
    Then it still seems that the arm wants `double` 8-byte aligned. No idea why, but that's the natural explanation. – Daniel Fischer May 26 '13 at 14:07
  • @Daniel Fischer but why gcc makes it works in x86 linux whose double is also 8-byte? – Ezio May 26 '13 at 14:10
  • But on x86, the _alignment_ of a `double` is only four bytes (one must read two words, so there's no reason that the first of the two words should be 8-byte aligned), so the `char` member is only followed by `4 - sizeof (char) = 3` bytes of padding. – Daniel Fischer May 26 '13 at 14:14
  • @Daniel Fischer but i'm still confused,both x86's and arm's bus is 32bit,why arm is still calcuate in 8-byte alignment? – Ezio May 26 '13 at 14:26
  • It would be 8-byte-aligned on x86 too if the x86 ABI were being designed today. The problem is that the x86 ABI was designed somewhere around 25 years ago without much foresight about how alignment might matter. ARM had the luxury of knowing what was important when the ABI was designed (and if I'm not mistaken, only the EABI got it right; I don't think the old ABI had 8-byte alignment, and it didn't even really have IEEE double). – R.. GitHub STOP HELPING ICE May 27 '13 at 01:58

2 Answers2

6

A double is always 8 bytes long, but the alignment requirements differ based on the architecture. In ARM (apparently, from your example) the requirement is to align doubles on an 8 byte boundary.

Structures are always padded with space to make their size a multiple of the field with the largest alignment requirement. In the example above, the compiler will put m1, then 3 (or 7) bytes of padding, then d1.

Just to be confusing, on x86 the alignment only NEEDS to be a 4-byte boundary, but GCC can optionally make it an 8 byte boundary for performance. From the gcc man page:

-malign-double

-mno-align-double

Control whether GCC aligns double, long double, and long long variables on a two word boundary or a one word boundary. Aligning double variables on a two word boundary will produce code that runs somewhat faster on a `Pentium' at the expense of more memory. Warning: if you use the -malign-double switch, structures containing the above types will be aligned differently than the published application binary interface specifications for the 386 and will not be binary compatible with structures in code compiled without that switch.

Dave B
  • 186
  • 3
  • in your opinion, why linux x86 reqire 4-byte alignment for double and x86 vc 6.0 require 8-byte ? – Ezio May 26 '13 at 15:10
  • It's just a matter of the ABI that VC follows being newer. The i386 ELF ABI that Linux/x86-32 uses is very old -- dating to the 1980s, if memory serves. Aligning doubles to only 4 bytes has been known to be bad for performance on x86 since the 1990s, which is approximately when Microsoft wrote the Win32 ABI. Note that if you compile your test program for Linux/x86-64, whose ABI was designed circa 2004, the struct will be 16 bytes. – zwol May 30 '13 at 16:06
  • (This should be a separate question, but for the sake of myself and others I ask) ... So if I send (TCP/UDP/Serialization_Of_Choice) a Double from an ARM to an x86, will the values be the same? – Xofo Aug 07 '19 at 16:46
2

To supplement Dave-B's answer,

The gcc changes include a note on an ABI change to align vectors larger than 8 bytes on an 8 byte boundary. Table 4.1 of the ARM AAPCS give alignment documentation,

Procedure Call Standard for the ARM Architecture
4.1 Fundamental Data Types
Type     Class       Byte size Byte alignment
Integral Unsigned    8             8
             double-word
Floating Double       8             8
Point     Precision

This is generally advantageous as the data will not straddle a cache line. Also, the ARM ldrd and strd are faster if the memory is aligned. As this is part of the ARM standard for C compiler inter-operability gcc should do this by default. Using attribute(packed) and optimizing for size -Os may change the alignment.

An internal bus used on many ARM processors is 64bit.

See also: ARM C calling convention

Community
  • 1
  • 1
artless noise
  • 21,212
  • 6
  • 68
  • 105
  • -Os does not break ABI and thus cannot change alignment. – R.. GitHub STOP HELPING ICE May 26 '13 at 15:13
  • @R Probably not, but if the structure is entirely in the compilation unit it might not align as strictly. Also see [gcc bugzilla](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27537), which seems quite appropriate for this question. I agree if the `struct` makes it to an external interface, then even *-Os* should align to 8 bytes on the ARM. – artless noise May 27 '13 at 01:41
  • The bug you linked is a much different issue. It's that the gcc developers decided to retroactively add an assumption that the caller aligns the stack pointer to an 8-byte boundary as part of the i386 ABI; it has nothing to do with the alignment requirements of different types. – R.. GitHub STOP HELPING ICE May 27 '13 at 01:55
  • No need to apologize. I agree it's interesting. – R.. GitHub STOP HELPING ICE May 27 '13 at 01:58