Рассмотрим следующую простую структуру:
struct A
{
float data[16];
};
Мой вопрос:
Предполагается, что платформа, где float
- это 32-битное число с плавающей точкой IEEE754 (если это вообще имеет значение), гарантирует ли стандарт C ++ ожидаемое расположение памяти для struct A
?Если нет, то что это гарантирует и / или каковы способы обеспечения гарантий ?
Под ожидаемым расположением памяти я имею в видучто структура занимает 16*4=64
байтов в памяти, каждый последовательный 4
байтов занят одним float
из массива data
.Другими словами, ожидаемая схема памяти означает следующие тестовые прохождения:
static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
(offsetof
здесь допустимо, поскольку A
- стандартная схема, см. Ниже)
В случае, если это вас беспокоит, тест фактически проходит на wandbox с gcc 9 HEAD.Я никогда не встречал комбинацию платформы и компилятора, которая бы свидетельствовала о том, что этот тест может провалиться, и я хотел бы узнать о них, если они существуют.
Почему кого-то это волнует:
- SSE-подобные оптимизации требуют определенной схемы памяти (и выравнивания, которое я игнорирую в этом вопросе, поскольку с ним можно справиться, используя стандартный спецификатор
alignas
). - Сериализация такогоstruct просто сводится к хорошему и переносимому
write_bytes(&x, sizeof(A))
. - Некоторые API (например, OpenGL, в частности, скажем, glUniformMatrix4fv ) ожидают такой точной компоновки памяти.Конечно, можно просто передать указатель на массив
data
, чтобы передать один объект этого типа, но для последовательности из них (скажем, для загрузки атрибутов вершин матричного типа) определенная структура памяти все еще необходима.
Что на самом деле гарантировано:
Это то, что, насколько мне известно, можно ожидать от struct A
:
- Это стандартный макет
- Как следствие стандартного макета, указатель на
A
может быть reinterpret_cast
на указатель на его первый элемент данных (который, предположительно, data[0]
?)т. е. там нет заполнения до первого члена.
Две оставшиеся гарантии, которые не (насколько мне известно), предоставляемые стандартом:
- Нет заполнения между элементами массива примитивного типа (яуверен, что это неверно, но мне не удалось найти подтверждающую ссылку),
- Заполнение отсутствует после массив
data
внутри struct A
.