Подтвердить что ты не робот

Выравнивание памяти: как использовать выравнивание/выравнивание?

Я работаю с разделяемой памятью прямо сейчас.

Я не могу понять alignof и alignas.

cppreference неясно: alignof возвращает "выравнивание", но что такое "выравнивание"? количество байтов для добавления для последующего выравнивания следующего блока? мягкий размер? Переполнение стека/записи в блогах также неясны.

Может кто-нибудь объяснить ясно alignof и alignas?

4b9b3361

Ответ 1

Выравнивание - это ограничение, на котором память может хранить значение первого байта. (Необходимо повысить производительность процессоров и разрешить использование определенных инструкций, которые работают только с данными с определенным выравниванием, например, SSE необходимо выровнять до 16 байтов, а AVX - до 32 байт.)

Выравнивание 16 означает, что адреса памяти, кратные 16, являются единственными действительными адресами.

alignas

принудительное выравнивание к требуемому количеству байтов (cppreference не упоминает об этом, но я думаю, что вы можете выровнять только по степеням 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);
}

Пример вывода:

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

другое ключевое слово

alignof

очень удобно, вы не можете сделать что-то вроде

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

но вы можете сделать

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

отметим, что на самом деле это более строго, чем простая операция "%" (модуль). На самом деле мы знаем, что что-то согласованное с 1024 байтами обязательно выравнивается с 1, 2, 4, 8 байтами, но

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

Чтобы быть более точным, "alignof" возвращает наибольшую степень 2, для которой что-то выравнивается.

Также alignof - это хороший способ заранее знать минимальное требование выравнивания для базовых типов данных (он, вероятно, вернет 1 для символов, 4 для float и т.д.).

Все еще законно:

alignas(alignof(float)) float SqDistance;

Что-то с выравниванием 16 затем будет помещено на следующий доступный адрес, который будет кратен 16 (может быть неявное дополнение из последнего использованного адреса).

Ответ 2

Выравнивание не является дополнением (хотя иногда выполняется добавление для удовлетворения требований к выравниванию). Это свойство intrisic типа С++. Чтобы поставить его в стандартное (3.11[basic.align])

Типы объектов имеют требования к выравниванию (3.9.1, 3.9.2), которые устанавливают ограничения на адреса, на которых может быть выделен объект этого типа. Выравнивание представляет собой целочисленное значение, определяемое реализацией, представляющее количество байтов между последовательными адресами, по которым может быть выделен данный объект. Тип объекта налагает требование выравнивания для каждого объекта этого типа; более строгое выравнивание можно запросить с помощью спецификатора выравнивания (7.6.2).

Ответ 3

Каждый тип имеет требование выравнивания. Как правило, это так, что переменные типа могут быть доступны эффективно, без необходимости заставить ЦП генерировать более одного доступа для чтения/записи, чтобы достичь любого данного члена типа данных. Кроме того, он также обеспечивает эффективное копирование всей переменной. alignof вернет требование выравнивания для данного типа.

alignas используется для принудительного выравнивания по типу данных (при условии, что он не менее строгий, чем то, что alignof сказал бы тип данных)