Когда мы не должны использовать #pragma pack? - PullRequest
16 голосов
/ 19 октября 2011

В C, когда мы используем структуры, когда было бы неуместно использовать # pragma pack директива ..?

дополнение к вопросу .....

Может кто-нибудь объяснить, как может произойти сбой доступа к невыровненным данным, особенно с указателем?

Ответы [ 5 ]

38 голосов
/ 19 октября 2011

Прошивка разработчика здесь. #pragma pack очень знакомая территория. Я объясню.

Как правило, вы не должны использовать #pragma pack. Да, это уменьшит ваши структуры в памяти, поскольку устранит все отступы между членами структуры. Но это может сделать доступ к тем членам намного дороже, так как члены больше не могут соответствовать их требуемому выравниванию. Например, в архитектурах ARM требуется, чтобы 4-байтовые числа были выровнены по 4 байта, но в упакованной структуре их может и не быть. Это означает, что компилятор должен добавить дополнительные инструкции для безопасного доступа к этому элементу структуры, или разработчик должен обращаться к нему побайтово и восстанавливать int вручную. В любом случае это приводит к большему количеству кода, чем к выровненному доступу, поэтому ваша структура в конечном итоге становится меньше, но ваш код доступа может оказаться медленнее и больше.

Вы должны использовать #pragma pack, когда ваша структура должна соответствовать точному макету данных. Обычно это происходит, когда вы пишете код, соответствующий спецификации передачи данных или доступа ... например, сетевые протоколы, протоколы хранения, драйверы устройств, которые обращаются к регистрам HW. В этих случаях вам может понадобиться #pragma pack, чтобы заставить ваши структуры соответствовать заданному макету данных. Это может повлечь за собой то же снижение производительности, что и в предыдущем абзаце, но может быть единственным способом соблюдения спецификации.

3 голосов
/ 19 октября 2011

Я бы сказал, что вы не должны упаковывать вещи, если для этого нет действительно веской причины.

Когда указан пакет, все отступы удаляются.Поэтому члены структуры могут быть не выровнены, что может иметь последствия для производительности.

1 голос
/ 20 ноября 2012

Директива #pragma pack предлагает способ выполнить это требование.Эта директива определяет выравнивание упаковки для элементов конструкции.Прагма вступает в силу при первом объявлении структуры после просмотра pragma.Компилятор Turbo C / C ++ не поддерживает эту функцию, компилятор VC ++ поддерживает.

1 голос
/ 19 октября 2011

В большинстве архитектур базовый доступ должен соответствовать выравниванию данных, к которым осуществляется доступ.

Это означает, что если у вас есть 32-битное значение, вы можете получить к нему эффективный доступ, если оно хранится по адресу, который делится на четыре.

Если вы используете #pragma pack, расположение переменной может быть любым, и компилятор должен обращаться к элементу по частям и объединять их вместе. Конкретно, ниже приведен сгенерированный код для чтения обычного int на V850E (популярном микроконтроллере во встроенном мире):

LD.W        a[zero],r5

Соответственно, ниже приведен код для доступа к int в упакованной структуре:

LD.BU       g+3[zero],r1
SHL         8,r1
LD.BU       g+2[zero],r6
OR          r1,r6
SHL         8,r6
LD.BU       g+1[zero],r7
OR          r6,r7
SHL         8,r7
LD.BU       g[zero],r1
OR          r7,r1

Другая причина не использовать упакованные структуры состоит в том, что невозможно разыменовать указатель на член упакованной структуры, если архитектура не поддерживает обращения к указателю без выравнивания. Причина этого в том, что тип точки будет простым указателем int, и компилятор не знает, что он должен обращаться к тому, на что он указывает, по частям.

Я бы настоятельно рекомендовал вам вообще не использовать «#pragma pack», если это не является абсолютно необходимым. Если у вас есть контроль над определением структуры, существуют методы, позволяющие убедиться, что структура структуры не содержит отступов. Если нет, лучшим подходом было бы скопировать любые невыровненные данные в новую, выровненную, структурированную и использовать их в вашем приложении.

0 голосов
/ 19 октября 2011

Вы никогда не должны использовать #pragma pack или подобное.Это всегда приводит к опасным проблемам переносимости.Например, рассмотрим структуру:

struct foo {
    char a;
    int b;
} bar;

и вызов scanf("%d", &bar.b).На машинах без несоответствующего доступа это вызовет ошибку (или повреждение памяти!) внутри scanf!Это потому, что &bar.b на самом деле не является действительным int * - он выровнен, но код, который он передал, не может этого знать и обойти, как это сделал бы компилятор, если вы только что написали bar.b = 42;.

Единственное предназначенное использование для упакованных структур - это сериализация, но это также приводит к непереносимым файлам.Вы должны просто написать правильные функции сериализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...