Как использовать #pragma pack (1) OR / Zp1, чтобы они влияли только на упаковку структур, определенных приложением, а не на структуры, определенные в Windows SDK? - PullRequest
1 голос
/ 15 апреля 2019

Я портирую свое приложение (смесь win32 и MFC), скомпилированное с использованием VC98 (созданное с использованием make-файлов в командной строке, НЕ IDE) (x86), в Visual Studio 2017 (x64). Приложение использует огромное количество структур C, и они упакованы с данными, скопированы в буфер и отправлены по N / W. Протокол связи требует, чтобы эти структуры вообще не имели дополнительного заполнения, чтобы отправленные данные соответствовали спецификациям, используемым для связи между клиентом (моим приложением) и сервером. Чтобы убедиться в этом, приложение использует / Zp для компиляции каждого файла.

После портирования на VS2017 (x64) с использованием / Zp (из IDE), когда я пытался запустить приложение, графический интерфейс приложения не запускается, и я получаю исключения из SDK и MFC, когда некоторые определенные SDK / MFC структуры являются доступ к приложению, например, OPENFILENAME. Итак, чтобы решить эту проблему, так как / Zp все еще определен на уровне проекта в VS2017, я использовал следующее, где мы включили windows.h:

#ifdef _WIN64
#pragma pack(push,8)
#endif
#include <windows.h>
#ifdef _WIN64
#pragma pack(pop)
#endif

Это решило проблему в некоторой степени, но я все еще получаю некоторые ошибки от MFC, и некоторые функции, такие как crypt API (MSCAPI), возможно, не работают, потому что есть другие заголовочные файлы, такие как windows.h, включенные моим приложением, которые также должны быть охраненным как выше.

В качестве альтернативы я также пытался вообще не использовать / Zp, а затем переходить к каждому заголовочному файлу и заключать все содержимое файла (после включений в системный заголовочный файл) между #pragma pack (1) и #pragma pack (). Это работает, но не является надежным и слишком утомительным для меня, чтобы сделать то же самое для 1000-х заголовочных файлов.

Итак, вкратце, мне нужен способ гарантировать, что все структуры C, определенные моим приложением, не используют никакие дополнения, но те, которые определены Windows SDK / MFC, продолжают использовать заполнение по умолчанию (возможно, 8 байтов). Любые идеи относительно того, как я могу решить эту проблему надежным способом с минимальным количеством изменений? Возможно, эта проблема не возникает и в VC98, потому что платформа x86 ИЛИ SDK, включенный в VC98, не делает никаких предположений относительно упаковки структур.

1 Ответ

1 голос
/ 16 апреля 2019

Передача данных бинарной структуры по сети или через файлы - очень хрупкий подход:

  • упаковка структур решает только проблемы выравнивания, если типы, используемые в определениях struct, сохраняют одно и то же представление. Проверьте определения низкоуровневых типов, используемых в ваших структурах: LONG по-прежнему 32-битный в 64-битной Windows (!), Но size_t имеет другой размер.
  • Порядок следования байтов может отличаться на разных машинах: x86 использует представление с прямым порядком байтов, тогда как некоторые другие процессоры, используемые в сотовых телефонах или планшетах, могут использовать байты с прямым порядком байтов. Невозможно принудительно настроить порядок байтов в памяти.
  • принудительное смещение элемента структуры может привести к неопределенному поведению на некоторых процессорах, x86 по умолчанию настроен как очень снисходительный, обычно это невозможно на других процессорах.
  • , несмотря на то, что это очень тонкая абстракция поверх аппаратного обеспечения, язык C не позволяет точно контролировать фактическое расположение, используемое для структур в памяти. Хорошим примером непереносимых отображений является реализация битовых полей. Ваши структуры могут иметь битовые поля, которые отображаются по-разному в 32-битной Windows и 64-битной архитектуре.

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

...