Могу ли я определить и изменить текущие настройки выравнивания данных для структур в gcc / g ++? - PullRequest
0 голосов
/ 20 февраля 2020

Мой вопрос основан на части этого вики-ответа на вопрос Почему sizeof для структуры не равен сумме sizeof каждого члена? (подчеркните мой):

"ВАЖНОЕ ПРИМЕЧАНИЕ. Стандарты C и C ++ утверждают, что выравнивание структуры определяется реализацией. Поэтому каждый компилятор может по-разному выравнивать данные, что приводит к различным и несовместимым макетам данных. По этой причине при работе с библиотеками, которые будут использоваться разными компиляторами, важно понимать, как компиляторы выравнивают данные. Некоторые компиляторы имеют параметры командной строки и / или специальные операторы #pragma для изменения выравнивания структуры settings."

  • Можно ли обнаружить и изменить текущую настройку выравнивания структуры в gcc / g ++?
  • И если да, как мне определить текущая настройка выравнивания + как я могу изменить ее в gcc / g ++?

Большое спасибо за вашу помощь.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Можно ли ... изменить текущую настройку выравнивания структуры в gcc / g ++?

Да. G CC Прагмы и параметры командной строки описаны в документации G CC.

Существует параметр командной строки:

-fpack-struct[=n]

Без указания значения, упаковать все элементы конструкции вместе без отверстий. Если указано значение (которое должно быть небольшой степенью двух), упакуйте элементы структуры в соответствии с этим значением, представляющим максимальное выравнивание (то есть объекты с требованиями выравнивания по умолчанию, превышающими это, выводятся потенциально невыровненными в следующем месте подгонки.

Предупреждение: ключ -fpack-struct заставляет G CC генерировать код, который не совместим двоично с кодом, сгенерированным без этого переключателя. Кроме того, он делает код неоптимальным. Используйте его для соответствия двоичный интерфейс приложения не по умолчанию.

И прагмы:

Для совместимости с компиляторами Microsoft Windows, G CC поддерживает набор # директивы прагмы, которые изменяют максимальное выравнивание элементов структур (кроме битовых полей нулевой ширины), объединений и классов, определенных впоследствии. Значение n ниже всегда должно быть небольшой степенью двойки и задает новое выравнивание в байтах.

  1. #pragma pack(n) просто устанавливает новое выравнивание. * 10 25 *
  2. #pragma pack() устанавливает выравнивание на то, которое действовало при запуске компиляции (см. Также параметр командной строки -fpack-struct [=], см. Опции Code Gen).
  3. #pragma pack(push[,n]) pushes текущая настройка выравнивания во внутреннем стеке, а затем при необходимости устанавливает новое выравнивание.
  4. #pragma pack(pop) восстанавливает настройку выравнивания до значения, сохраненного в верхней части внутреннего стека (и удаляет эту запись в стеке). Обратите внимание, что # pragma pack([n]) не влияет на этот внутренний стек; таким образом, можно иметь #pragma pack(push), за которым следуют несколько #pragma pack(n) экземпляров и завершать их одним #pragma pack(pop).

Некоторые цели, например, i386 и powerp c, поддерживают ms_struct #pragma, которая представляет структуру в виде документированных __attribute__ ((ms_struct)).

  1. #pragma ms_struct on поворотов в макете для объявленных структур.
  2. #pragma ms_struct off отключает макет для объявленных структур.
  3. #pragma ms_struct reset возвращается к макету по умолчанию.

Можно ли обнаружить ... текущую настройку выравнивания структуры в gcc / g ++?

Многое зависит от того, что вы подразумеваете под "обнаруживать". Существует следующая опция командной строки:

-frecord-gcc-switches

Этот переключатель заставляет командную строку, которая использовалась для вызова компилятора, записываться в создаваемый объектный файл. Этот переключатель реализован только для некоторых целей, и точный формат записи зависит от целевого и двоичного формата файла, но обычно он принимает форму раздела, содержащего текст ASCII.

Если такая опция использовалась , затем вы можете определить, использовался ли -fpack-struct [= n], проверив двоичный файл.


Если вы просто хотите узнать выравнивание определенного типа, вы можете использовать alignof оператор. Если вы хотите узнать максимальное выравнивание любого скалярного типа, вы можете использовать alignof(std::max_align_t). Вы можете указать классы или массивы для более строгого выравнивания, чем они были бы с alignas. Если это превышает выравнивание std::max_align_t, то класс считается выровненным.

1 голос
/ 20 февраля 2020

Для C ++, начиная с C ++ 11, вы можете использовать alignas и alignof для переносного задания и получения выравнивания любого типа. Ниже приведен пример из cppreference для alignof, где вы можете увидеть оба в действии:

#include <iostream>

struct Foo {
    int   i;
    float f;
    char  c;
};

struct Empty {};

struct alignas(64) Empty64 {};

int main()
{
    std::cout << "Alignment of"  "\n"
        "- char             : " << alignof(char)    << "\n"
        "- pointer          : " << alignof(int*)    << "\n"
        "- class Foo        : " << alignof(Foo)     << "\n"
        "- empty class      : " << alignof(Empty)   << "\n"
        "- alignas(64) Empty: " << alignof(Empty64) << "\n";
}

Возможный вывод:

Alignment of
- char             : 1
- pointer          : 8
- class Foo        : 4
- empty class      : 1
- alignas(64) Empty: 64

Следует отметить, что alignas не позволит вам использовать выравнивание, которое менее строго, чем то, что требуется объекту по умолчанию. Это означает, что вы не можете использовать его для «упаковки», удаления заполнения структуры данных.

...