4

Code 1:-

struct emp
{
  char a;
  double b;
};
int main()
{
    struct emp e;
    printf("%p    %p", (void*)&e.a, (void*)&e.b);
}

Output on my computer:-

OO28FF00    0028FF08

As the size of char and double is '1' and '8' respectively and hence the 0028FF00 and 0028FF08 are multiples of '1' and '8' respectively.

Code 2:-

struct emp
{
  char a;
  long double b;
};
int main()
{
    struct emp e;
    printf("%p    %p    \n", (void*)&e.a,(void*)&e.b);
}

The output is :-

0028FF00    0028FF04

As the size of char and long double is '1' and '12' respectively but 0028FF04 is not a multiple of '12'.

Why padding is not applied in this case?

kevin gomes
  • 1,775
  • 5
  • 22
  • 30
  • 1
    First use `%p` instead of `%u` and cast addresses to `void*` – Grijesh Chauhan Feb 08 '14 at 07:26
  • @GrijeshChauhan : that I know but my question is regarding padding. – kevin gomes Feb 08 '14 at 07:31
  • question is regarding padding and a good question indeed, but using in-proper format type is undefined behavior in C. So I suggest you try again with `%p` and cast addresses to `void*` and update question. – Grijesh Chauhan Feb 08 '14 at 07:36
  • @GrijeshChauhan : I did it but the question still remains same. – kevin gomes Feb 08 '14 at 07:41
  • correct way is `printf("%p %p", (void*)&e.a, (void*)&e.b);` – Grijesh Chauhan Feb 08 '14 at 07:43
  • In my system, `long double` is 16, not 12 – Jay Feb 08 '14 at 07:44
  • Can you also print `sizeof(long double)`? – nodakai Feb 08 '14 at 07:45
  • Alignment is not necessarily the same as size. – n. m. could be an AI Feb 08 '14 at 07:46
  • @Jay : but in mine its 12 – kevin gomes Feb 08 '14 at 07:46
  • 1
    alignment relates to the native architecture's size, not the structure size. A structure of size 512 bytes would also be aligned to 4/8/16 bytes depending on system, not 512 byte – phuclv Feb 08 '14 at 07:46
  • @LưuVĩnhPhúc : then why in my first example `double` is aligned by 8 bytes not 4 – kevin gomes Feb 08 '14 at 07:47
  • as far as I can guess is that padding is done in powers of 2, like 1,2,4,8,16.......but 12 in my case is acception – kevin gomes Feb 08 '14 at 07:50
  • @kevingomes, maybe you can use `__attribute__((__packed__))` to suppress padding. – Jay Feb 08 '14 at 07:53
  • because the FPU loads/stores double in 8 bytes by native, not 4-by-4, or you're specifying `-malign-double` in gcc. 12-byte data may be different because they may need 2 loads, look at or `-m96bit-long-double` – phuclv Feb 08 '14 at 07:55
  • @Jay : If I supress padding in this question, then this would not be a question..... – kevin gomes Feb 08 '14 at 07:55
  • @LưuVĩnhPhúc : you mean to say that 12 is stored in parts like 4,4,4 – kevin gomes Feb 08 '14 at 07:56
  • Which compiler is this? Is it an old DOS compiler by any chance? – Dmitri Feb 08 '14 at 08:03
  • @Dmitri : mine is mingw gcc and I think that in old compilers, there was no padding facility. – kevin gomes Feb 08 '14 at 08:04
  • no, [alignment](https://en.wikipedia.org/wiki/Data_structure_alignment) is an old feature from the era of RISC, it has come decades before mingw was born – phuclv Feb 08 '14 at 08:13
  • @LưuVĩnhPhúc : but tc is not having alignment... – kevin gomes Feb 08 '14 at 08:15
  • In 16-bit DOS times, memory is a constraint so maybe they default to use unaligned data to preserve memory, but it doesn't mean that the compiler don't support padding https://sites.google.com/site/sanselgroup/c/structure-padding – phuclv Feb 08 '14 at 08:34
  • @LưuVĩnhPhúc : but I ran the same code on tc and it did not showed any sign of padding – kevin gomes Feb 08 '14 at 08:39
  • Yes, did you read the links on my comment above? They said that the default option is not padding any data, so you have to enable some switch to use it. I don't know x87 assembly so I don't know how they load long double values but [gcc](http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/i386-and-x86_002d64-Options.html) said that Pentium or newer prefer long double to be aligned to 8 bytes, maybe you need to change some option to change the alignment mode – phuclv Feb 08 '14 at 08:45

3 Answers3

3

A long double is an 80 bit floating point so you need 10 bytes. 10 is really not a very good size though, thus Intel 32 bit processors decided on 12 bytes. 12 is a multiple of 4 which represents 32 bits (3 x 32 bits). This is considered aligned because a 32 bit processor only needs 4 bytes alignment, so the 12 bytes is aligned at any 4 bytes boundary. Obviously, the compiler knows what it's doing and it always tries to generate the smallest possible structure.

This being said, this is where you see that you cannot use a struct declaration and hope to save it as is in a file... at least not with the default C types (you can use int32_t, uint64_t, etc. to get exactly what you want, but there is no equivalent for floating point numbers...)

As someone commented, on a 64 bit architecture, long double is 16 bytes. A waste of 6 bytes... but it makes the type 64 bit aligned all the time.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • No, that's not what Intel decide. Only 32 bit loads/stores on x86 are aligned to 4 byte, not all other data type. And that's just a recommendation, not requirement since they can still operate with unaligned data, althoug with reduce performance. On modern x86 processors, even 32-bit mode requires double to be 8-byte aligned, SSE data must align to 16 bytes, 32 bytes for AVX (and may be 64 bytes for the new AVX-512). – phuclv Feb 08 '14 at 08:13
  • Yeah... the processor may be setup to accept any alignment, or crash if loading unaligned data with the "wrong" instruction. It's a bit more complicated than I explain here, but the OP only asked about long double and C struct alignment. To learn more about all the subtleties, I'd recommend reading the **Intel 64/IA32 Architectures Software Developers Manual**. – Alexis Wilke Feb 08 '14 at 08:29
2

Wikipedia has a table of typical alignments:

x86 has flexible memory access instructions, so there rules are up to the compiler designers' decision. We can only imagine why they thought there are the most reasonable.

I found @LưuVĩnhPhúc 's comment very educative. Although long double is 12 bytes on your platform (GCC?) it was 4 bytes aligned by the same reason why a 512 bytes struct will not be 512 bytes aligned; there will be too much waste in space. I guess the designers of GCC thought accessing double variables should be done in the least possible latency at the cost of some space (up to 7 bytes.)

nodakai
  • 7,773
  • 3
  • 30
  • 60
0

Well, as far as I know padding and data alignment heavily depend on the target architecture, compiler optimization options and overall quality of the optimizator. Thus if you don't specifically care about alignment, you get a "quazi-optimal" structures and the compiler is free to decide what is better for this particular set of optimization options (whether -Os or -O is used and so on). If you wish to have a specific alignment, you should use compiler-specific options to tune the things. For GCC and CLang use __packed__ attribute, for MSVC use #pragma pack. See pragma pack(1) nor __attribute__ ((aligned (1))) works for more info

Community
  • 1
  • 1
user3159253
  • 16,836
  • 3
  • 30
  • 56