Nano Hash - криптовалюты, майнинг, программирование

Когда мы не должны использовать пакет #pragma?

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

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

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

19.10.2011

  • Использование #pragma pack довольно редко - и вы потенциально отказываетесь от переносимости вашего кода, поскольку упаковка зависит от системы. 19.10.2011
  • Лучше задать вопрос: когда будет уместно использовать #pragma pack ?. (Ответ: очень редко и только если вы знаете, что делаете.) 19.10.2011
  • Возможной причиной использования pack(1) могут быть структуры данных, которые должны быть переданы непосредственно в сеть без какого-либо перевыравнивания. Например, структура с символом и 16-битным целым числом действительно имеет длину всего 3 байта. 19.10.2011
  • @alk: Даже в этом случае вам нужно беспокоиться о порядке байтов. Гораздо лучше просто написать как unsigned char[3]. 20.10.2011

Ответы:


1

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

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

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

19.10.2011
  • -1 для Вы должны использовать пакет #pragma. Есть много других способов справиться с этой ситуацией, которые действительно допустимы C. 20.10.2011
  • Р.. можете ли вы привести несколько примеров множества других способов справиться с этой ситуацией? Я также всегда использовал пакет #pragma именно так, как предлагает Эндрю. Спасибо. 01.10.2012
  • По своему опыту работы со встроенными платформами и сетевым взаимодействием я обнаружил, что пакет #pragma чрезвычайно полезен. Если вы знаете, как правильно упорядочить и выровнять свою структуру для данной архитектуры (и компилятора), снижения производительности быть не должно. 19.06.2013

  • 2

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

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

    19.10.2011
  • Не только последствия для производительности — несогласованный доступ к определенным типам данных приводит к исключению (т. е. сбою) на многих архитектурах. 19.10.2011
  • Конечно. Инструкции SSE/AVX приведут к исключениям. (если вы не используете смещенную загрузку/хранилище) 19.10.2011

  • 3

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

    Это означает, что если у вас есть 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', за исключением случаев крайней необходимости. Если у вас есть контроль над определением структуры, существуют методы, позволяющие убедиться, что макет структуры не содержит отступов. Если нет, лучшим подходом будет копирование любых невыровненных данных в новую, выровненную структуру и использование ее в вашем приложении.

    19.10.2011

    4

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

    20.11.2012

    5

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

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

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

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

    19.10.2011
  • Даунвотер, не хочешь объяснить? Я считаю, что ответил на вопрос и предложил полезную дополнительную информацию о том, почему. 20.10.2011
  • Только что наткнулась на эту ветку. Я не минусовал тебя, но не решаюсь поставить плюс. Причина в том, что вы сказали, что никогда не должны использовать. Но я довольно часто использую #pragma pack(push, 4) в коде, который мне нужен для переноса между ARM и x64, поэтому я не согласен с утверждением, что #pragma pack никогда не следует использовать. ИМХО, следует ли вам его использовать, зависит от того, насколько переносимым вам нужен ваш код. 16.04.2015
  • @ToddLehman: я не понимаю, как #pragma pack может помочь вам добиться переносимости между ARM и x64. 16.04.2015
  • — Это не помогает мне добиться переносимости как таковой. Просто я могу использовать его в коде, который мне нужен для переносимости между ARM и x64 без потери переносимости. То есть, это не повредит переносимости в тех случаях, когда я его использую. Например, я широко использую #pragma pack(push, 4) в structs, содержащем как uint64_t, так и uint32_t, так что оно всегда кратно 4 байтам, а не 8. Мне нравится pragma pack, и я настоятельно рекомендую использовать его в ограниченных ситуациях. Даже на платформе x64 быстрее перебирать большую таблицу 12-байтовых структур, чем 16-байтовые. 17.04.2015
  • @ToddLehman: 4 года спустя после того, как он попросил разъяснений, и вы уверены, что даже поклялись бы, что в то время вы не были голосующим против? *саркастично* :D 16.07.2015
  • Я использую #pragma pack в этом случае использования: одна dll c# для всех платформ, которые определяют структуру, которая передается в собственный код. Структура в C# применяет определенную упаковку с атрибутом StructLayout. Без #pragma pack на нативной стороне я не могу обеспечить безопасное копирование структур на всех платформах. Таким образом, ваш аргумент Это всегда приводит к опасным проблемам с переносимостью, просто неверен. 11.04.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..