Рассмотрим следующую простую структуру:
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
). - Сериализация такой структуры просто сводилась бы к красивому и переносимому
write_bytes(&x, sizeof(A))
. - Некоторые API (например, OpenGL, в частности, скажем, glUniformMatrix4fv) ожидают точно такого же расположения памяти. Конечно, можно просто передать указатель на массив
data
для передачи одного объекта этого типа, но для их последовательности (скажем, для загрузки атрибутов вершин матричного типа) по-прежнему требуется определенное расположение памяти.
Что на самом деле гарантируется:
Вот чего, насколько мне известно, можно ожидать от struct A
:
- Это стандартный макет.
- Как следствие стандартного макета, указатель на
A
может бытьreinterpret_cast
указателем на его первый член данных (который, предположительно,data[0]
?), т. е. нет заполнения before первый член.
Две оставшиеся гарантии, которые не (насколько мне известно) предусмотрены стандартом:
- Нет отступов между элементами массива примитивного типа (уверен, что это неверно, но мне не удалось найти подтверждающую ссылку),
- Отступы после массива
data
внутриstruct A
отсутствуют.
N
подобъектов типаT
. ” Издание 1998 г. имеет идентичный текст, за исключением слов «подобъекты» в 8.3.4, разделенных дефисом. - person Eric Postpischil   schedule 12.04.2019struct { char x[2]; }
четырьмя байтами, если ее целевое оборудование имеет сильный уклон в сторону четырехбайтовой адресации памяти, и реализация решила сделать все структуры выровненными по крайней мере по четырем байтам, чтобы удовлетворить Требование стандарта C к одному представлению для всех указателей структур. Я ожидаю, что C++ похож, но не могу с уверенностью говорить о нем… - person Eric Postpischil   schedule 12.04.2019struct { float data[16]; }
не будет иметь завершающего дополнения ни в одной обычной реализации C или C++ — для этого нет причин ни на одной нормальной целевой платформе. Но в отсутствие явной спецификации в стандарте C++ единственный способ гарантировать это для проекта — потребовать, чтобы любая реализация C++, используемая для его компиляции, удовлетворяла этому свойству. Это можно проверить с помощью утверждения. - person Eric Postpischil   schedule 12.04.2019sizeof
должны проходить для массива.sizeof
должен включать любые отступы в конце. - person luk32   schedule 12.04.2019