Когда использовать выравнивание в 1 байт

149
01 апреля 2019, 07:50
#include <iostream>
struct S1
{
    char a;
    int b;
    char d;
};
#pragma pack(1)
struct S2
{
    char a;
    int b;
    char d;
};
int main()
{
 std::cout<<sizeof(S1)<<std::endl;
 std::cout<<sizeof(S2)<<std::endl;
}

output:

12

6

Когда стоить использовать выравнивание в 1 байт, только при небольших объемах памяти? Какие плюсы и минусы?

Answer 1

Пройдемся по плюсам и минусам.

  • плюсы
    • структуры имеют меньший размер, меньше расход памяти
    • бывает удобно при сериализации/десериализации
    • иногда упрощает низкоуровневый код.
  • минусы
    • внутренние поля могут быть выровненные "неудобно" для процессора и можно получить замедление работы программы
    • иногда выравнивание может быть не таким, как ожидает программист. Может быть разным на разных платформах или версиях компилятора. Поэтому для сериализации иногда может и не подойти. Нужно как минимум жестко контролировать через sizeof и другие методы.
    • выравнивание очень специфично работает, если есть битовые поля (специфично - не так как ожидает программист).

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

  • нужно хранить много-много структур и скоростью работы программы можно пожертвовать. Но возможно можно просто переупорядочить поля.
  • пишется простое ipc и размер имеет значение (хотя лучше взять что то готовое)
  • используется api операционной системы и "так нужно".
  • хочется поэкспериментировать и поизучать компилятор глубже.

P.S. Кстати, в коде есть проблема. После того, как применили упаковку, нужно её аккуратно вернуть назад. Да, в этом примере ничего не будет, но если pragma pack попадет в header файл, может быть большая беда - одна и та же структура будет иметь разный размер в разных единицах компиляции, поля будут выровнены по разному.

#pragma pack(push, 1)
struct Foo
{
    // ...
};
#pragma pack(pop)

P.S.S. Можно ещё на хабре почитать.

Answer 2

Когда использовать? Тогда, когда Вы точно знаете, что делаете и это абсолютно необходимо. Какие минусы? Неопределённое поведение. Вот Ваш модифицированный код:

#include <iostream>
using std::cout;
struct S1
{
    char a;
    int b;
    char d;
};
#pragma pack(1)
struct S2
{
    char a;
    int b;
    char d;
};
int main()
{
    cout << sizeof(S1) << "\n";
    cout << sizeof(S2) << "\n";
    cout << alignof(int) << "\n";
    S2 s2;
    size_t address = reinterpret_cast<size_t>(&s2.b);
    cout << "Var address: " << std::hex << address  << "\n";
    cout << "Properly aligned? " << std::boolalpha << (address % alignof(int) == 0);
}

Последняя строчка скорее всего выведет false, что означает, что переменная типа int расположена по адресу, который противоречит требования выравнивания для этого типа (стандарт [basic.align]). А раз это противоречит требованиям стандарта, значит Ваша программа некорректна.

READ ALSO
Как изменить свойства файла С++

Как изменить свойства файла С++

Нужно удалять файлы, в том числе и файлы "Только чтение"Если в свойствах стоит галочка "Только чтение", то через remove() удалить не получается

169
Как поставить библиотеку С++ без или с Cmake

Как поставить библиотеку С++ без или с Cmake

Я нашел оболочку для curl и пытаюсь ее "собрать" Что я сделал:

160
Написать метод объединения строк

Написать метод объединения строк

Собственно само задание звучит так:

154