5

This is about memory alignment. In code below, I expected that the offset of b inside the structure to be 8 (32-bit machine). See here. There by, making b always occur within a cache line. However, that's not the case. The member b in a global object of struct test1 seems to be aligned. I am not sure if its by chance or compiler is doing this deliberately.

I wanted to understand why compiler is not padding 4 bytes after a.

struct test1
{
int a;
double b;
}t1;

int main()
{
struct test1 *p = malloc(sizeof(struct test1));
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double));
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1));

printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b));

return 0;
}

The output is...

sizes int 4, float 4, double 8, long double 12
offset of b 4

address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0

I am using standard gcc compiler on ubuntu 10.04

Community
  • 1
  • 1
Chethan
  • 905
  • 1
  • 10
  • 18
  • For one thing, if the CPU can deal with misaligned operands, there's no problem. Now, why your compiler is tightly packing structures, is a question. How are you compiling the code? Are there any hidden compile options coming from makefiles or whatever the compiler might be pulling from its configuration files? – Alexey Frunze Feb 15 '13 at 11:43
  • @Alexey, no, its just gcc test.c; ./a.out – Chethan Feb 15 '13 at 11:45
  • I get the same results when compiling with gcc 4.6.3 using "default" options and -m32 (I've got a 64-bit OS, so default is 64-bit, and in that case, it gives me an 8-byte alignment). – Mats Petersson Feb 15 '13 at 11:45
  • Likely on your environment, 32bit alignment for everything is enough, and aligning doubles on 64bit boundaries does not gain you anything. This isn't uncommon for 32bit architectures, as they like to access stuff in 32bit chunks. – PlasmaHH Feb 15 '13 at 11:51
  • 3
    gcc aligns doubles on linux x86 to 4 bytes. Use -malign-double if you'd want 8 byte alignment. The question you link to states false facts, as alignment is a platform dependent matter, and even windows and linux platforms aligns a double differently on x86 – nos Feb 15 '13 at 12:00
  • 1
    This is Unix i386 ABI. double are required to be aligned on 4 bytes boundary. Other ABIs (and other architectures) may have other requirements. – Yann Droneaud Feb 15 '13 at 13:47

3 Answers3

5

According to the System V ABI for i386, page 28, double only gets 4 bytes alignment, but compilers are recommended to provide an option for 8 bytes as well. It appears this is what is implemented by GCC on Linux, the option being called -malign-double.

Another alternative is to use -m64 to get x86-64 object code, which is already the default on some systems including Mac OS X.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
4

I expected that the offset of b inside the structure to be 8 (32-bit machine). See here

Your references explain why it could be advantageous to 8-align doubles. This doesn't amount to a guarantee that doubles will always be 8-aligned. If your sources say that they're always 8-aligned, and you observe an implementation in which they aren't, then your sources are wrong.

From the GCC man page:

Aligning "double" variables on a two word boundary will produce code that runs somewhat faster on a Pentium at the expense of more memory.

So GCC's stated reason for 4-alignment is to save memory. You can use -malign-double and -mno-align-double to control that, although of course you risk creating binary incompatibilities if you share structs between code compiled with conflicting options. For particular objects/struct members you can use GCC's own __attribute__((aligned)), _Alignas (in C11) or alignas (in C++11), all of which can take an integer constant to specify the required alignment.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0

There is no guarantee about alignment, at all, in ANSI C.

The alignment happens with automatic variables more than with anything declared on the heap. If you're on a POSIX OS, use memalign(3) to receive memory that you're sure is aligned. Malloc may return memory at any offset. You can use compiler directives like __attribute__ ((__packed__)) to put in your own alignments.

Anonymous
  • 21
  • 2