Is It Always the Case That Sizeof(T) >= Alignof(T) for All Object Types T

Is it always the case that sizeof(T) >= alignof(T) for all object types T?

At least in standard C++, for anything you can make an array of (with length > 1), this will have to be true. If you have

Foo arr[2];

and alignof(Foo) > sizeof(Foo), then arr[0] and arr[1] can't both be aligned.

As Zalman Stern's example shows, though, at least some compilers will allow you to declare a type with alignment greater than its size, with the result that the compiler simply won't let you declare an array of that type. This is not standards-compliant C++ (it uses type attributes, which are a GCC extension), but it means that you can have alignof(T) > sizeof(T) in practice.

The array argument assumes sizeof(Foo) > 0, which is true for any type supported by the standard, but o11c shows an example where compiler extensions break that guarantee: some compilers allow 0-length arrays, with 0 sizeof and positive alignof.

Is sizeof(T) == sizeof(int)?

You essentially are asking, given:

struct T {
U handle;
};

whether it's guaranteed that sizeof(T) == sizeof(U). No, it is not.

Section 9.2/17 of the ISO C++03 standard says:

A pointer to a POD-struct object, suitably converted using a
reinterpret_cast, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides) and vice versa.

Suppose you have an array of struct T. The vice versa part means that the address of any of the T::handle members must also be a valid address of a struct T. Now, suppose that these members are of type char and that your claim is true. This would mean that struct T would be allowed to have an unaligned address, which seems rather unlikely. The standard usually tries to not tie the hands of implementations in such a way. For your claim to be true, the standard would have to require that struct T be allowed to have unaligned addresses. And it would have to be allowed for all structures, because struct T could be a forward-declared, opaque type.

Furthermore, section 9.2/17 goes on to state:

[Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment.]

Which, taken a different way, means that there is no guarantee that there will never be padding.

How can std::aligned_storage expose correctly aligned storage for any object?

Per [meta.trans.other]/2,

It is implementation-defined whether any extended alignment is supported.

It's pretty annoying when they specify stuff like this after the big table without a pointer. I've just added the sentence to cppreference.

What's the age before __STDCPP_DEFAULT_NEW_ALIGNMENT__ appears

The fundamental alignment is represented by alignof(std::max_align_t). It means that any supported alignment is less than this value.
std::max_align_t was introduced by C++11. It means that any type of alignment requirement can be met as long as alignof(std::max_align_t) is followed.

The introduction of __STDCPP_DEFAULT_NEW_ALIGNMENT__ in C++17 is accompanied by the introduction of operator new(std::size_t count, std::align_val_tal). In order to distinguish what alignment requirements will use the align version of operator new, and what alignment requirements will use the non-align version of new, __STDCPP_DEFAULT_NEW_ALIGNMENT__ gives a clear definition. Any alignment requirements greater than this value will use the align version of new. In addition, all non-align versions of new are used.

So since C++17 introduced key points
When overloading operator new, if the non-aligned version of operator new overloaded version is called, it means that the alignment requirement of this allocation is less than or equal to __STDCPP_DEFAULT_NEW_ALIGNMENT__, but you still don’t know whether the allocation comes from new char or new short or new long. According to the classic solution, set the alignment to the maximum alignment. So at least this value is greater than or equal to alignof(std::max_align_t). Take MSVC as an example, alignof(std::max_align_t) is 8, then this value must be greater than or equal to 8. However, if the alignment requirement is 16, the non-aligned version of operator new will also be called, and the 8-alignment will not meet the requirement. So this value must be promoted to __STDCPP_DEFAULT_NEW_ALIGNMENT__ in order to satisfy any alignment requirements for calling the non-align version new.

Why doesn't the compiler set __STDCPP_DEFAULT_NEW_ALIGNMENT__ to alignof(std::max_align_t)? This is determined by the hardware requirements and the implementation of the compiler. Each compiler will set up according to their actual needs, we just need to follow the standards. We can also study why MSVC is 16, but remember that other platforms will have another value.

So before C++17 and after C++11, how can we align without __STDCPP_DEFAULT_NEW_ALIGNMENT__? Note: Before C++17, there was no __STDCPP_DEFAULT_NEW_ALIGNMENT__ nor operator new(std::size_t count, std::align_val_t al). At this time, all operator new will call the non-align version. Then this version of the operator implementation must be the largest case, because the actual alignment requirements of the actual allocation type cannot be known. We just need to follow alignof(std::max_align_of). A paradoxical problem is that I just used __STDCPP_DEFAULT_NEW_ALIGNMENT__ with C++17 on my local Windows. I already know that the hardware and compiler requirements of my platform are 16. Then when I switch to C++11 compilation, shall I still use 16? The answer is no, because C++11 does not have any standard that tells us something like __STDCPP_DEFAULT_NEW_ALIGNMENT__, so its compiler will not assume that its operator new will be aligned according to 16. We only need to follow the alignment requirement alignof(std::max_align_t) established by the current standard.

What about C++98 era that before C++11, how should overloaded operator new be aligned? Because there is no standard to regulate a unified place for obtaining alignment information, then application programmers can only restrict themselves according to the actual situation of their own platforms.

Why isn't sizeof for a struct equal to the sum of sizeof of each member?

This is because of padding added to satisfy alignment constraints. Data structure alignment impacts both performance and correctness of programs:

  • Mis-aligned access might be a hard error (often SIGBUS).
  • Mis-aligned access might be a soft error.

    • Either corrected in hardware, for a modest performance-degradation.
    • Or corrected by emulation in software, for a severe performance-degradation.
    • In addition, atomicity and other concurrency-guarantees might be broken, leading to subtle errors.

Here's an example using typical settings for an x86 processor (all used 32 and 64 bit modes):

struct X
{
short s; /* 2 bytes */
/* 2 padding bytes */
int i; /* 4 bytes */
char c; /* 1 byte */
/* 3 padding bytes */
};

struct Y
{
int i; /* 4 bytes */
char c; /* 1 byte */
/* 1 padding byte */
short s; /* 2 bytes */
};

struct Z
{
int i; /* 4 bytes */
short s; /* 2 bytes */
char c; /* 1 byte */
/* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

One can minimize the size of structures by sorting members by alignment (sorting by size suffices for that in basic types) (like structure Z in the example above).

IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.

Is it possible to have a type with a larger alignment than its own size?

The Rust reference has this to say about size and alignment (emphasis mine):

Size and Alignment


[...]

The size of a value is the offset in bytes between successive elements in an array with that item type including alignment padding. The size of a value is always a multiple of its alignment. The size of a value can be checked with the size_of_val function.

Determining maximum possible alignment in C++

In C++0x, the Align template parameter of std::aligned_storage<Len, Align> has a default argument of "default-alignment," which is defined as (N3225 §20.7.6.6 Table 56):

The value of default-alignment shall be the most stringent alignment requirement for any C++ object type whose size is no greater than Len.

It isn't clear whether SSE types would be considered "C++ object types."

The default argument wasn't part of the TR1 aligned_storage; it was added for C++0x.

how and why sizeof(a)/sizeof(a[0]) in c is used to calculate the number of elements in an array

According to the C Standard (6.5.3.4 The sizeof and alignof operators)

2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer. If
the type of the operand is a variable length array type, the operand
is evaluated; otherwise, the operand is not evaluated and the result
is an integer constant.

So if you have an array as for example

int a[N];

where N is some integer value then expression

sizeof( a )

yields the number of bytes occupied by the array. As the array has N elements and each element in turn occupies sizeof( int ) bytes then

sizeof( a ) == N * sizeof( int )

or what is the same

sizeof( a ) == N * sizeof( a[0] )

As result you can calculate N the following way

N = sizeof( a ) / sizeof( a[0] )

It is useful if you do not know the exact size of an array for example because its size depends on the number of initializers.

For example

int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );

Take into account that sometimes beginners make an error.

Let's assume that you have a function declaring an array as a parameter.

For example

void f( int a[10] );

and the function can be called like

int a[10];

f( a );

Beginners usually write in the body of the function the following expression

void f( int a[10] )
{
size_t n = sizeof( a ) / sizeof( a[0] );
//...
}

However it is a wrong code. The problem is that parameters declared like arrays are adjusted to pointers to the type of the array element. So the function declaration actually looks like

void f( int *a );

and within the function in expression

    size_t n = sizeof( a ) / sizeof( a[0] );

parameter a is pointer. That is it is equivalent to

    size_t n = sizeof( int * ) / sizeof( int );

Depending on the used system pointers occupy either 4 or 8 bytes. So you will get either 2 or 1 if sizeof( int ) is equal to 4.

You will not get the number of elements in the array that was used as the argument.

Pointers do not keep an information about whether they point to a single object or the first object of some array.

In this case you should declare the function with second parameter that specifies the number of elements in the array. For example

void f( int *a, size_t n );


Related Topics



Leave a reply



Submit