Мне нужно выравнивание в C++?

Я уверен, что знаю. Библиотека матриц Eigen3, вероятно, намного быстрее, чем любая из моих собственных реализаций матриц благодаря выравниванию.

Недавно я начал исследовать выравнивание с помощью C++. Я наткнулся на функции alignas и alignof и решил провести несколько тестов.

Моя первая находка заключалась в том, что члены структуры выравниваются автоматически. Возьмем для примера следующую структуру:

struct MyStruct
{
    char m_c; // 1 byte
    double m_x; // 8 bytes
};

и сравните с этим:

struct MyAlignedStruct
{
    char m_c; // 1 byte
    alignas(8) double m_x; // 8 bytes
};

где я использовал alignas вместо добавления элемента заполнения (char [7]), что, согласно моему пониманию, эквивалентно.

Теперь программа просмотра памяти для обеих структур показала следующее:

62 00 00 00 8e a8 79 35 00 00 00 00 00 00 10 40 // MyStruct
62 ff ff ff 24 00 00 00 00 00 00 00 00 00 10 40 // MyAlignedStruct

Первый байт соответствует символу ('b'). При использовании Mystruct следующие 7 байтов заполняются что-нибудь, а последние 8 байтов представляют собой двойное значение. При использовании MyAlignedStruct происходит нечто очень похожее. Функция sizeof () возвращает 16 байтов для обеих структур (я ожидал 9 байтов для MyStruct).

Итак, вот мой первый вопрос: зачем мне выравнивание, если компилятор выравнивается сам по себе?

Моя вторая находка было то, что alignas (..) не ускоряет мою программу. Мой эксперимент заключался в следующем. Представьте себе следующую простую структуру:

struct Point
{
    double m_x, m_y, m_z;
};

Если я заполняю вектор экземплярами этой структуры и предполагаю, что первый экземпляр выровнен по 32 байта, каждая структура будет занимать 24 байта, а последовательность байтов больше не будет выровнена по 32 байта. Честно говоря, я не уверен, как можно увеличить скорость за счет выравнивания, иначе, скорее всего, я бы здесь не писал. Тем не менее, я использовал alignas для получения следующей структуры:

alignas(32) struct Point
{
    double m_x, m_y, m_z;
};

Теперь непрерывные экземпляры Point будут начинаться с числа, кратного 32 байтам. Я протестировал обе версии: после заполнения огромного вектора экземплярами структур я просуммировал все двойники и записал время. Я не обнаружил различий между 32-байтовой выровненной структурой и другой.

Итак, мой второй вопрос такой же, как и мой первый: зачем мне выравнивания?

Простой ответ заключается в том, что обычно вы этого не делаете, но если вам абсолютно необходимо работать с необработанной памятью и чужеродными структурами данных, вы можете найти alignas полезным. Большинство вещей, с которыми помогает alignas, раньше было возможно, но требовало усилий. Типичный пример - это что-то вроде Struct* s = new (new alignas(Struct) char [ sizeof(Struct)]) Struct, но вам нужно нужно, чтобы создавать объекты на месте в необработанной памяти.

Gem Taylor 15.03.2018 17:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
171
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Why do I need alignas if the compiler aligns on its own?

Несколько причин вне моей головы:

  1. Компилятор может быть настроен для упаковки структур, как описано здесь:

    Заставить структуру C++ плотно упаковать

    но вы хотите, чтобы какая-то конкретная структура имела выровненные члены

  2. Вам нужно выравнивание, выходящее за рамки того, что требует тип, например

    alignas(1024) struct MyStruct
    {
        char m_c; // 1 byte
        alignas(32) double m_x; // 8 bytes
    };
    

    Это могло быть связано с аппаратными ограничениями, например. у вас есть карта, которая может захватывать вещи из памяти с разрешением 1024 страницы; а затем на этой карте доступ к данным осуществляется блоками по 32 байта. Пример будет соответствовать этим требованиям, вместо того, чтобы вставлять фиктивные поля.

  3. Набросок / нарезка типа: вы можете получить адрес массива из:

    struct s1
    {
        char m_c;
        uint32_t m_d;
        char m_e;
    };
    

    но на самом деле я использовал

    struct s2
    {
        char m_c;
        mystery_type_with_size_64_bits m_d;
        char m_e;
    };
    

    поэтому, даже если вы хотите работать с m_d как с uint32_t, вам также необходимо правильно настроить m_e.

Другие вопросы по теме