Memory alignment : how to use alignof / alignas?
Asked Answered
D

5

118

I work with shared memory right now.

I can't understand alignof and alignas.

cppreference is unclear : alignof returns "alignment" but what is "alignment" ? number of bytes to add for the next block to be aligned ? padded size ? Stack overflow / blogs entries are unclear too.

Can someone explain clearly alignof and alignas ?

Dextrality answered 13/6, 2013 at 15:44 Comment(5)
cppreference is trying to be a reference rather than a tutorialSommerville
@Cubbi: you can also check at cplusplus.com, there is debate wich site is better, for certain topics cplusplus is better, for other cppreference is better, I found that both sites certain times are not eonughArv
@DarioOO I was only answering why cppreference doesn't explain the concept of alignment on the alignof page (it does now, on the work-in-progress object page). I don't see how cplusplus.com is relevant.Sommerville
Also see Where can I use alignas() in C++11.Skelton
All the answers talk about performance, but there are platforms where the hardware isn't able to load a misaligned intElemental
A
131

Alignment is a restriction on which memory positions a value's first byte can be stored. (It is needed to improve performance on processors and to permit use of certain instructions that works only on data with particular alignment, for example SSE need to be aligned to 16 bytes, while AVX to 32 bytes.)

Alignment of 16 means that memory addresses that are a multiple of 16 are the only valid addresses.

alignas

force alignment to the required number of bytes. You can only align to powers of 2: 1, 2, 4, 8, 16, 32, 64, 128, ...

#include <cstdlib>
#include <iostream>

int main() {
    alignas(16) int a[4];
    alignas(1024) int b[4];
    printf("%p\n", a);
    printf("%p", b);
}

example output:

0xbfa493e0
0xbfa49000  // note how many more "zeros" now.
// binary equivalent
1011 1111 1010 0100 1001 0011 1110 0000
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2

the other keyword

alignof

is very convenient, you cannot do something like

int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error

but you can do

assert(alignof(a) == 16);
assert(alignof(b) == 1024);

note that in reality this is more strict than a simple "%" (modulus) operation. In fact we know that something aligned to 1024 bytes is necessarily aligned to 1, 2, 4, 8 bytes but

 assert(alignof(b) == 32); // fail.

So to be more precise, "alignof" returns the greatest power of 2 to wich something is aligned.

Also alignof is a nice way to know in advance minimum alignment requirement for basic datatypes (it will probably return 1 for chars, 4 for float etc.).

Still legal:

alignas(alignof(float)) float SqDistance;

Something with an alignment of 16 then will be placed on the next available address that is a multiple of 16 (there may be a implicit padding from last used address).

Arv answered 15/1, 2014 at 23:46 Comment(12)
Unlike sizeof, alignof can only be applied to a type-id.Seizure
is alignof() (and the counterpart alignas()) evaluated at compile time , so no runtime overhead?Paulitapaulk
no. It is not possible, the compiler may do that as optimization in very few cases, but in general it will not know how memory addresses are aligned before evaluating the 2 functions. Just look at assembly generated by my example: goo.gl/ZbemBFArv
@Serthy To clarify alignof is a compile-time constant. alignas is not, and will have to be supported by your implementation of new (requirement of the standard), or by a custom std allocator.Heresiarch
Good answer, but it needs a treatment of struct and members of the struct that are static. alignas is turning out to be much more finicky than __attribute__((aligned)), especially under compilers like Clang.Skelton
"Alignment of 16 means that memory addresses that are a multiple of 16 are the only valid addresses." Where does this comes from? According to the C++ Stadnard: An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated..Stepup
What is the difference apart wording? Maybe I user a top vague term "valid".Arv
This answer is kind of misleading. GNU C supports alignof(b) as an extension (vs. ISO C++ only allowing alignof(type-id)), but it's only useful on arrays declared with alignof(). If you had int *p, alignof(p) is still a compile-time constant (alignof(int*)) not isolating the lowest set bit in the pointer. To check alignment at runtime on a pointer, you normally cast to uintptr_t and do p & 15 == 0 or something. You don't need to check alignment when you already declared your array with alignas.Calmative
alignof tells you the minimum allowed alignment for a type. alignof(T) < sizeof(T) tells you it might not be naturally-aligned. Or alignas(sizeof(T)) T foo; gives you a naturally-aligned object. (Useful e.g. if you want to later use C++20 atomic_ref<> on it, or in the implementation of atomic<T>). Or yes, alignas(alignof(T)) other_type foo; might make sense in some case. Not with both being float; plain float foo already gives foo at least alignof(float).Calmative
I think this last example is the most useful part of your whole answer!: alignas(alignof(float)) float SqDistance;, because it teaches me how to easily enforce alignment of a memory pool I'm using to store class objects by constructing them into the pool using "placement new". Now, I can ensure my memory pool has proper alignment for these objects of type T, like this: alignas(alignof(T)) char buf[sizeof(T)];. See also the "Placement new" section here: en.cppreference.com/w/cpp/language/new.Jack
what is SSE? what is AVX? Please provide a link, I've searched online but there are too many abbreviations and I don't know what to search for :)Cowey
CPU architecture instruction sets.Arv
S
17

Alignment is not padding (although padding is sometimes introduced to satisfy alignment requirements). It is an intrisic property of a C++ type. To put it in standardese (3.11[basic.align])

Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment specifier (7.6.2).

Sommerville answered 13/6, 2013 at 18:20 Comment(4)
Very interesting. Would you mind giving some examples ? Does alignof(struct X) == sizeof(struct X) ? Why not ?Dextrality
@Dextrality no, except by concidence: struct X { char a; char b} has size 2 and alignment requirement 1, on sane systems (it can be allocated at any address because a char can be allocated at any address)Sommerville
alignment req of 1 ???? Oh I get it : I thought that alignment was always on "natural" 32bits/64bits boundaries but apparently not. That explains things... So on usual machines, alignof() result will always max at 4 (32bits) or 8 (64bits) Am I right ?Dextrality
@Dextrality "natural" alignof will max out at alignof(std::max_align_t), which is 16 on my linux (regardless of whether compiling -m32 or -m64), but you can make it stricter with alignasSommerville
J
8

Each type has an alignment requirement. Generally, this is so variables of the type can be accessed efficiently, without having to cause the CPU to generate more than one read/write access in order to reach any given member of the datatype. Furthermore, it also ensure efficient copying of the entire variable. alignof will return the alignment requirement for the given type.

alignas is used to force an alignment on a datatype (so long as it is not less stringent that what alignof said datatype would return)

Jeannajeanne answered 13/6, 2013 at 19:47 Comment(0)
B
8

Alignment is a property related with memory address. Simply we can say than if an address X is aligned to Z then x is a multiple of Z ,that is X = Zn+0. Here the important thing is Z is always a power of 2.

Alignment is a property of a memory address, expressed as the numeric address modulo a power of 2. For example, the address 0x0001103F modulo 4 is 3. That address is said to be aligned to 4n+3, where 4 indicates the chosen power of 2. The alignment of an address depends on the chosen power of 2. The same address modulo 8 is 7. An address is said to be aligned to X if its alignment is Xn+0.

The above statement is found on microsoft c++ reference .

If a data item is stored in the memory with an address which is aligned to its size , then that data item is said to be naturally aligned , else misaligned. For eg : if an integer variable with size 4 bytes is stored in an address which is aligned to 4 , then we can say that the variable is naturally aligned , that is the address of the variable should be a multiple of 4.

The compilers always tries to avoid misalignments . For simple datatypes the addresses are chosen such that it is a multiple of the size of the variable in bytes. The complier also pads suitably in the case of structures for natural alignment and access.Here the structure will be aligned to the maximum of the sizes of different data items in the structure.eg:

    struct abc
   {
        int a;
        char b;
   };

Here the structure abc is aligned to 4 which is the size of int member which is obviously greater than 1 byte(size of char member).

alignas

This specifier is used to align user defined types like structure , class etc to a particular value which is a power of 2.

alignof

This is a kind of operator to get the value to which the structure or class type is aligned. eg:

#include <iostream>
struct alignas(16) Bar
{
    int i; // 4 bytes
    int n; // 4 bytes
    short s; // 2 bytes
};
int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}
Bangalore answered 22/9, 2020 at 17:35 Comment(0)
H
7

To understand alignas and alignof you must know What data alignment mean

Good guide for it https://developer.ibm.com/articles/pa-dalign//

Alignment (nutshell)

Explanation 1

Data alignment means putting the data in memory at address equal to some multiple of the word size.

Explanation 2

Alignment is a property of a memory address, expressed as the numeric address modulo a power of 2. For example, the address 0x0001103F modulo 4 is 3. That address is said to be aligned to 4n+3, where 4 indicates the chosen power of 2. The alignment of an address depends on the chosen power of 2. The same address modulo 8 is 7. An address is said to be aligned to X if its alignment is Xn+0.

CPUs execute instructions that operate on data stored in memory. The data are identified by their addresses in memory. A single datum also has a size. We call a datum naturally aligned if its address is aligned to its size. It's called misaligned otherwise. For example, an 8-byte floating-point datum is naturally aligned if the address used to identify it has an 8-byte alignment.

Okay. You understood "data alignment" Congratulations!

What does mean alignas

Explanation

alignas (N) specifies will place data only in address of a multiple of N

N - the number modulo a power of 2

Syntax:

alignas( the numeric address modulo a power of 2 )
alignas( alignof(type-id) )
alignas( type-id )

The alignas specifier may be applied to:

  • the declaration or definition of a class / struct / union or enumeration;

  • the declaration of a non-bitfield class data member;

  • the declaration of a variable, except that it cannot be applied to the following:

    • a function parameter;
    • the exception parameter of a catch clause.

Example:

struct alignas(256) name1 // every object of type name1 will be aligned to 256-byte boundary
{
    float test[4];
};

alignas(128) char name2[128]; // the array "name2" will be aligned to 128-byte boundary

Addition 1

The alignas type specifier is a portable, C++ standard way to specify custom alignment of variables and user defined types.

Addition 2

#include <iostream>

struct alignas(16) Bar
{
    int i;       // 4 bytes
    int n;      // 4 bytes
    alignas(4) char arr[3];
    short s;          // 2 bytes
};

int main()
{
    std::cout << alignof(Bar) << std::endl;
}

When multiple alignas specifiers are encountered, the compiler will choose the strictest one, (the one with the largest value).

output: 16

Addition 3

alignas cannot be used to give a type a smaller alignment than the type would have without this declaration

What does mean alignof

Syntax:

alignof( type-id )

Returns a value of type std::size_t

Same definition have sizeof( type-id )

What's the difference between sizeof and alignof?

struct MyStruct
{
    int x;
    double y;
    char z;
};
    
main() 
{
    std::cout << "The sizeof(MyStruct): " << sizeof(MyStruct) << std::endl;
    std::cout << "The alignof(MyStruct): " << alignof(MyStruct) << std::endl;
}
output:
    The sizeof(MyStruct): 24
    The alignof(MyStruct): 8

Problem in structure padding

Structure padding is a concept in C that adds the one or more empty bytes between the memory addresses to align the data in memory

More information: Struct padding in C++

Addition

The result is a constant expression of type std::size_t, i.e., it can be evaluated at compile time.

More information here: Source 1, Source 2,

Hypertensive answered 27/8, 2021 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.