Выравнивание элементов структуры в GCC

Я переношу проект msvc, в котором есть несколько библиотек, и каждая библиотека имеет определенное выравнивание элементов структуры. Использование выравнивания по умолчанию вызвало множество фатальных проблем с несовпадением, и поиск в Google сказал мне, что я могу решить эту проблему, установив выравнивание для каждой структуры/класса/объединения вручную с помощью флага __attribute__ ((aligned (MY_ALIGN))), однако есть одна вещь, которая меня беспокоит:

Давайте для простоты скажем, что проект A использует выравнивание по 1 байту, а проект B, который активно использует функциональность проекта A и включает множество его заголовков, имеет выравнивание по 16 байтам. Будут ли с этим проблемы, или я слишком много думаю, и это просто сработает? У меня плохое предчувствие, что при сборке библиотеки компилятор msvc устанавливает выравнивание для каждой структуры во всех заголовках (независимо от того, включены ли они в проект или на них ссылаются источники). Это правда? И если это так, скажите, пожалуйста, как мне установить выравнивание для эмуляции настройки выравнивания элементов структуры MSVC?


person Anonymous    schedule 20.07.2011    source источник
comment
Если вы не используете типы SIMD (SSE), у вас действительно не должно возникнуть проблем, если вы используете выравнивание по умолчанию. Если вы получаете ошибки, это потому, что вы делаете что-то ужасное в своем коде, который должен быть исправлен.   -  person jalf    schedule 20.07.2011
comment
Что ж, расширения SSE широко используются, и в них много кода, который требует определенного выравнивания...   -  person Anonymous    schedule 20.07.2011
comment
Учитывая SSE, вы должны иметь возможность настроить компилятор для вывода MOVUPS и т.п. вместо MOVAPS. Это решает вашу проблему переносимым способом. Второй вариант — использовать библиотеку, которая исправляет выравнивание по 16 байтам, третий — создать/интегрировать такую ​​библиотеку из вашего проекта. В любом случае, вы должны исправить выравнивание структур и элементов внутри заголовков, а не в настройках проекта или флагах компилятора.   -  person dascandy    schedule 20.07.2011
comment
моя точка зрения заключается в том, что нормальные типы правильно распределяются компилятором, если вы явно не нарушаете его (выполняя опасные приведения, которые полагаются на неопределенное поведение). Поэтому, если вы получаете ошибки выравнивания за пределами материала SSE, это может указывать на более глубокую проблему с вашим кодом.   -  person jalf    schedule 20.07.2011
comment
Dascandy, подскажите, пожалуйста, как настроить компилятор Apple GCC 4.2.1?   -  person Anonymous    schedule 20.07.2011
comment
вообще не используйте -fpack-struct, пусть компилятор определяет, как выравнивать вещи. Для типов SSE я не уверен, что GCC вообще генерирует какие-либо движения SSE. Если вы используете библиотеку SSE, она должна позаботиться о выравнивании с помощью __attribute__((aligned(16))) или аналогичного. Для выравнивания вы можете предположить, что любой бит данных, который начинается с его естественного выравнивания, не будет дополнен каким-либо компилятором. Для систем, ориентированных на производительность, это все еще верно, но только для типов, больших или равных его базовому типу (int). Таким образом, двойные числа всегда выровнены по 8 байтам и не будут заполняться, если они есть, но два char[3] могут получить байт заполнения.   -  person dascandy    schedule 20.07.2011


Ответы (2)


Я не думаю, что с этим должны быть проблемы. Просто помните, что невыровненный доступ (минимум 4 байта, я думаю, в большинстве систем) будет стоить вам (хотя вы сэкономите место, хотя и не так много в некоторых ситуациях). Сами структуры имеют атрибут, и компилятор будет выполнять всю арифметику указателя, поэтому, пока заголовки не путаются с определениями друг друга, все должно быть в порядке.

person Jesus Ramos    schedule 20.07.2011
comment
это может зависеть от архитектуры, для которой вы компилируете. Некоторые ЦП не допускают невыровненный доступ к определенным типам переменных (например, даже адреса для доступа int необходимы, адреса для двойного доступа должны делиться на 8, ...). В остальном я не вижу никаких проблем, пока выравнивание используется для структур, которым оно нужно, а не включено глобально. - person Tobias Langner; 20.07.2011
comment
Да, это была моя точка зрения (несогласованный доступ не имеет большого значения). Пока выравнивание не переопределяется где-то, все в порядке. Лично я не беспокоюсь об этом, поскольку компилятор знает лучше. - person Jesus Ramos; 20.07.2011
comment
Спасибо за ваши ответы, но проект переносится на платформу Mac OS X, где неправильное выравнивание приводит к сбою приложения, поэтому невыровненный доступ на самом деле является очень большой проблемой... - person Anonymous; 20.07.2011
comment
Это нормально, вы можете сохранить свое выравнивание, пока заголовки не конфликтуют друг с другом. - person Jesus Ramos; 20.07.2011
comment
Спасибо, Иисус! :) Не могли бы вы сказать мне, что вы подразумеваете под конфликтом заголовков? Заголовки проекта A включены в исходники проекта B, а определенные в них объекты широко используются в проекте B... - person Anonymous; 20.07.2011
comment
Под конфликтом я подразумеваю, что если я определяю структуру myStruct1 с выравниванием 1, а затем в заголовке B я переопределяю выравнивание на 4, это может вызвать проблемы, но я считаю это маловероятным. - person Jesus Ramos; 21.07.2011

Во-первых, каждый заголовок #include в вашем исходном файле обрабатывается буквально, независимо от того, находится ли он в том же проекте или нет.

Это определенно может привести к некоторым проблемам. Например, проект A определяет структуру и выравнивает все ее элементы по границе байта (упаковывается) и экспортирует функцию, принимающую указатель на эту структуру. Затем, если проект B по какой-то причине скомпилирован в такой среде, что одна и та же структура выравнивается по-разному, это сделает невозможным передачу адреса экземпляра этого struct непосредственно в эту экспортированную подпрограмму. У них разные sizeof по крайней мере в A и B.

Вот простое правило:
1) если вы собираетесь взаимодействовать с какой-то внешней скомпилированной библиотекой, вы должны убедиться, что выравнивание структуры соответствует выравниванию, используемому компилятором библиотеки. Это касается структур, присутствующих в заголовках библиотек. Хорошие библиотеки пытаются свести к минимуму усилия, предоставляя некоторым компиляторам #pragma для обеспечения правильного выравнивания.
2) если вы используете структуры в каком-то своем проекте, вы можете оставить его в покое, просто напишите переносимый код, который не зависит при некотором определенном выравнивании это будет делать.

person unkulunkulu    schedule 20.07.2011