Is the size of a struct required to be an exact multiple of the alignment of that struct?

前端 未结 9 2063
萌比男神i
萌比男神i 2020-11-28 13:00

Once again, I\'m questioning a longstanding belief.

Until today, I believed that the alignment of the following struct would normally be 4 and the size would normall

相关标签:
9条回答
  • 2020-11-28 13:12

    It is possible to produce a C or C++ typedef whose alignment is not a multiple of its size. This came up recently in this bindgen bug. Here's a minimal example, which I'll call test.c below:

    #include <stdio.h>
    #include <stdalign.h>
    
    __attribute__ ((aligned(4))) typedef struct {
        char x[3];
    } WeirdType;
    
    int main() {
        printf("sizeof(WeirdType) = %ld\n", sizeof(WeirdType));
        printf("alignof(WeirdType) = %ld\n", alignof(WeirdType));
        return 0;
    }
    

    On my Arch Linux x86_64 machine, gcc -dumpversion && gcc test.c && ./a.out prints:

    9.3.0
    sizeof(WeirdType) = 3
    alignof(WeirdType) = 4
    

    Similarly clang -dumpversion && clang test.c && ./a.out prints:

    9.0.1
    sizeof(WeirdType) = 3
    alignof(WeirdType) = 4
    

    Saving the file as test.cc and using g++/clang++ gives the same result.

    Notably however, MSVC on Windows does not seem to reproduce any behavior like this.

    0 讨论(0)
  • 2020-11-28 13:16

    One definition of alignment size:

    The alignment size of a struct is the offset from one element to the next element when you have an array of that struct.

    By its nature, if you have an array of a struct with two elements, then both need to have aligned members, so that means that yes, the size has to be a multiple of the alignment. (I'm not sure if any standard explicitly enforce this, but because the size and alignment of a struct don't depend on whether the struct is alone or inside an array, the same rules apply to both, so it can't really be any other way.)

    0 讨论(0)
  • 2020-11-28 13:17

    The standard says (section [dcl.array]:

    An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.

    Therefore there is no padding between array elements.

    Padding inside structures is not required by the standard, but the standard doesn't permit any other way of aligning array elements.

    0 讨论(0)
  • 2020-11-28 13:17

    So to split your question up into two:

    1. Is it legal?

    [5.3.3.2] When applied to a class, the result [of the sizeof() operator] is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

    So, no, it's not.

    2. Well, why isn't it?

    Here, I cna only speculate.

    2.1. Pointer arithmetics get weirder
    If alignment would be "between array elements" but would not affect the size, zthigns would get needlessly complicated, e.g.

    (char *)(X+1) != ((char *)X) + sizeof(X)
    

    (I have a hunch that this is required implicitely by the standard even without above statement, but I can't put it to proof)

    2.2 Simplicity
    If alignment affects size, alignment and size can be decided by looking at a single type. Consider this:

    struct A  {  int x; char y;  }
    struct B  { A left, right;   }
    

    With the current standard, I just need to know sizeof(A) to determine size and layout of B.
    With the alternate you suggest I need to know the internals of A. Similar to your example2: for a "better packing", sizeof(example) is not enough, you need to consider the internals of example.

    0 讨论(0)
  • 2020-11-28 13:17

    C++ doesn't explicitly says so, but it is a consequence of two other requirements:

    First, all objects must be well-aligned.

    3.8/1 says

    The lifetime of an object of type T begins when [...] storage with the proper alignment and size for type T is obtained

    and 3.9/5:

    Object types have *alignnment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an implementation-defined integer value representing a number of bytes; an object is allocated at an address that meets the alignment requirements of its object type.

    So every object must be aligned according to its alignment requirements.

    The other requirement is that objects in an array are allocated contigulously:

    8.3.4/1:

    An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.

    For the objects in an array to be contiguously allocated, there can be no padding between them. But for every object in the array to be properly aligned, each individual object must be padded so that the byte immediately after the end of the object is also well aligned. In other words, the size of the object must be a multiple of its alignment.

    0 讨论(0)
  • 2020-11-28 13:19

    The standard says very little about padding and alignment. Very little is guaranteed. About the only thing you can bet on is that the first element is at the beginning of the structure. After that...alignment and padding can be anything.

    0 讨论(0)
提交回复
热议问题