wangt0907
wangt0907

Reputation: 247

Would compiler secretly increase struct's alignment?

I have a struct of 8-bytes alignment, but when I define some variables of this type continuously but not in an array, it seems to be 16-bytes alignment. My question is, does the compiler increase its alignment for some purpose?

My test code is:

#include <stdio.h>
#include <stdint.h>
struct a{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;

int main(){
    printf("%lx\n", (uintptr_t)&a1);
    printf("%lx\n", (uintptr_t)&a2);
    printf("%lx\n", (uintptr_t)&a3);
    return 0;
}

And the output is:

601030
601050
601070

Upvotes: 0

Views: 104

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754520

On a 64-bit Unix machine (a Mac running macOS Sierra 10.12.6, using GCC 7.1.0), this code:

#include <stdio.h>
#include <inttypes.h>
struct a
{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;
struct a a4[4];

int main(void)
{
    printf("sizeof(struct a) = %zu\n", sizeof(struct a));
    printf("a1 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a1);
    printf("a2 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a2);
    printf("a3 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a3);
    for (int i = 0; i < 4; i++)
        printf("a4[%d] = 0x%.16" PRIXPTR "\n", i, (uintptr_t)(void *)&a4[i]);
    return 0;
}

produces this result:

sizeof(struct a) = 24
a1 = 0x0000000106776020
a2 = 0x0000000106776040
a3 = 0x0000000106776060
a4[0] = 0x0000000106776080
a4[1] = 0x0000000106776098
a4[2] = 0x00000001067760B0
a4[3] = 0x00000001067760C8

Note that the three standalone structures are laid out on 32-byte boundaries, but those in the array are laid out on 24-byte boundaries, as would be expected given the size of the structure (24 bytes).

By contrast (and contrary to an earlier edition of this answer), compiling with Clang (Apple LLVM version 8.1.0 (clang-802.0.42)), produces the result:

sizeof(struct a) = 24
a1 = 0x0000000102ACE020
a2 = 0x0000000102ACE038
a3 = 0x0000000102ACE050
a4[0] = 0x0000000102ACE070
a4[1] = 0x0000000102ACE088
a4[2] = 0x0000000102ACE0A0
a4[3] = 0x0000000102ACE0B8

Note that the single structures are now laid out on 24-byte boundaries (or, at least, 24 bytes apart instead of 32 as with GCC).

I don't have an explanation for why GCC adds the space, but the compiler is perfectly at liberty to do so. Both compilers are correct — the result is simply different.

Upvotes: 5

Related Questions