Упаковка структур в MSVC

Предварительный вопрос как правильно интерпретировать этот WAVEFORMATEX из декомпилированных необработанных байтов?

В этом вопросе комментарий заставил меня понять, что sizeof(WAVEFORMATEX)не равно 18, как Windows (кажется) этого ожидает.

Однако я не указываю ключ /Zp или /pack, поэтому компилятор должен использовать выравнивание по умолчанию. Почему моя система сообщает sizeof(WAVEFORMATEX) = 20? У меня х86. В моем файле compile_commands.json указано следующее:

{
  "directory": "E:\\FOO",
  "arguments": ["D:\\Programme\\Visual Studio 2022\\VC\\Tools\\MSVC\\14.40.33807\\bin\\HostX64\\x86\\cl.exe", "/c", "/nologo", "/Zi", "/FS", "/Fdbuild\\windows\\x86\\debug\\compile.foo.pdb", "/WX", "/Od", "/std:clatest", "/MTd", "/IFOO", "/DXAUDIO2_HELPER_FUNCTIONS", "/DWIN32_LEAN_AND_MEAN", "/DNOMINMAX", "/D_CRT_SECURE_NO_WARNINGS", "/DCOBJMACROS", "/DCINTERFACE", "/DDO_LOG", "/D_DEBUG", "/D_USE_MATH_DEFINES", "/IE:\\FOO\\build\\.packages\\z\\zlib\\v1.3.1\\55fd28c48bc34b35b89c569e2dd7bcce\\include", "/IE:\\FOO\\build\\.packages\\x\\xaudio2redist\\1.2.11\\163bc5c6e48e49d98ea66f724aede6bf\\include", "/Fobuild\\.objs\\foo\\windows\\x86\\debug\\FOO\\specific\\windows\\dxsound.c.obj", "FOO\\specific\\windows\\dxsound.c"],
  "file": "FOO\\specific\\windows\\dxsound.c"
},

Я компилирую для x86_x64 и использую стандарт C11.

Страница MSDN WAVEFORMATEX.

typedef struct tWAVEFORMATEX {
  WORD  wFormatTag;
  WORD  nChannels;
  DWORD nSamplesPerSec;
  DWORD nAvgBytesPerSec;
  WORD  nBlockAlign;
  WORD  wBitsPerSample;
  WORD  cbSize;
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;

Пожалуйста, поместите сюда соответствующий код.

Barmar 30.07.2024 19:47

какой код? Я спрашиваю, почему _STATIC_ASSERT(sizeof(WAVEFORMATEX) == 18); в принципе терпит неудачу.

Raildex 30.07.2024 19:48

Покажите, пожалуйста, структуру WAVEFORMATEX. Вероятно, требуется 4-байтовое выравнивание.

Barmar 30.07.2024 19:48

Например. если первый член требует выравнивания по 4 байта, то это требуется для всей структуры, поэтому в конце будет дополнение.

Barmar 30.07.2024 19:49
WORD имеет размер 4 байта, поэтому структура требует выравнивания 4.
Barmar 30.07.2024 19:51

@Barmar Learn.microsoft.com/en-us/cpp/build/reference/… Прочтите предупреждение. Я не уточняю /Zp. WAVEFORMATEX — это структура Win32, поэтому я не могу изменить ее выравнивание.

Raildex 30.07.2024 19:51

Извините, меня смутили размеры WORD и DWORD.

Barmar 30.07.2024 19:54

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

Barmar 30.07.2024 19:55

Об этом сообщает простая программа MSVC (64-бит) 18.

Weather Vane 30.07.2024 20:23

...но если я определю внешне идентичное struct, его размер будет 20. Я не вижу никакой подсказки в mmeapi.h.

Weather Vane 30.07.2024 20:31

@WeatherVane, только если вы перезапишете естественную упаковку. Должно быть 20 байт

RbMm 30.07.2024 20:32

@RbMm Нет, и я не понимаю, где mmeapi.h это делает.

Weather Vane 30.07.2024 20:33

...и определение заключено в #ifndef _WAVEFORMATEX_, поэтому оно должно быть определено в windows.h. Когда я опускаю #include <mmeapi.h>, программа все равно компилируется и запускается.

Weather Vane 30.07.2024 20:37

@WeatherVane: Заголовки Windows обычно содержат <pshpack1.h>. Возможно, это связано с проблемой, с которой сталкивается ОП. Существует множество заголовков, которые не следует включать напрямую и, вероятно, в них отсутствует эта директива.

cremno 30.07.2024 20:41

@cremno да, Windows.h довольно маленький и включает в себя кучу других заголовков.

Weather Vane 30.07.2024 20:45

@WeatherVane: В документации WAVEFORMATEX даже сказано, что вам нужно включать mmeapi.h, а не Mmreg.h там, где фактически определена структура. Очень вероятно, что проблема в этом.

cremno 30.07.2024 20:48

@cremno Mmreg.h делает #include "pshpack1.h". Ни то, ни другое включать не нужно, только Windows.h.

Weather Vane 30.07.2024 20:52

@WeatherVane, я не могу увидеть, где твоя ошибка, но #include <mmeapi.h > и C_ASSERT(sizeof(WAVEFORMATEX)==20);

RbMm 30.07.2024 20:57

@RbMm какая ошибка? Размер 18.

Weather Vane 30.07.2024 21:00

@WeatherVane, конечно, размер должен быть 20, а не 18.

RbMm 30.07.2024 21:01

@RbMm размер 18, как показывает небольшая тестовая программа, независимо от того, #include <mmeapi.h> я или нет, в этом нет необходимости.

Weather Vane 30.07.2024 21:02

@WeatherVane #include <mmreg.h > использует #pragma pack(push,1) и размер 18, если #include <mmeapi.h > пакет не перезаписывается и размер 20

RbMm 30.07.2024 21:04

внутри mmreg.h существуют #include "pshpack1.h" в начале и #include "poppack.h" в конце

RbMm 30.07.2024 21:07

@RbMm, ты не можешь просто включить mmreg.h, не включая сначала Windows.h. И если вы это сделаете, вам не нужно будет включать какой-либо другой заголовок Windows. Я не понимаю, к чему вы это ведете. Пользователь cremno уже размещал подобную информацию. Что вы добавляете?

Weather Vane 30.07.2024 21:10

@WeatherVane - конечно, я тоже включаю windows.h раньше, но здесь это не имеет отношения.

RbMm 30.07.2024 21:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
25
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Почему моя система сообщает sizeof(WAVEFORMATEX) = 20?

Компилятор предназначен для выравнивания членов DWORD по четырем байтам. Если структура начинается с четырехбайтовой границы, все члены в ней будут выровнены так, как задумано компилятором: члены WORD будут выровнены как минимум по двум байтам, а члены DWORD будут как минимум по четырем байтам. выровнено. Это не будет справедливо для членов DWORD, если структура начинается с границы, не кратной четырем байтам.

Если длина структуры составляла 18 байт и был объявлен их массив, то два соседних элемента в массиве не могли оба начинаться с четырехбайтовых границ. Поэтому компилятор добавляет два байта заполнения в конец массива, чтобы размер структуры составил 20 байт.

Нужно ли указывать упаковку, когда я хочу взаимодействовать с API WIn32? Я сомневаюсь, что мне нужно изменить выравнивание

Raildex 30.07.2024 20:24

@Raildex Win32 API ожидает 8-байтовое выравнивание во всех структурах API. Какую структуру структуры ожидают заголовочные файлы Windows SDK? /Zp8

Remy Lebeau 30.07.2024 20:37

@Raildex тебе не нужен. при естественном (не перезаписанном) выравнивании все будет ок. эта структура имеет размер 4 байта и размер 20 байт. размер всегда несколько выравнивается

RbMm 30.07.2024 20:59

@RemyLebeau, конечно, не 8-байтовое выравнивание для всех структур API. как пример WAVEFORMATEX выровнено только 4 байта. wiapi ждет естественного выравнивания, если оно не специально перезаписано пакетом #pragma и __declspec(align)

RbMm 30.07.2024 21:00
Ответ принят как подходящий

Скорее всего, вы включили неправильный заголовок для WAVEFORMATEX. В разделе требований вы можете найти правильный. Но будьте осторожны, поскольку структура определена в mmeapi.h, а заголовок, который вы должны включить, - Mmreg.h.

Итак, рабочий минимальный пример будет:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmreg.h>

static_assert(sizeof(WAVEFORMATEX) == 18);
static_assert(_Alignof(WAVEFORMATEX) == 1);

Против. неверный:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmeapi.h>

static_assert(sizeof(WAVEFORMATEX) == 20);
static_assert(_Alignof(WAVEFORMATEX) == 4);

Спасибо. Я дополнительно включил mmreg.h перед windows.h из-за автоматического завершения заголовка. Я этого не уловил. Спасибо!

Raildex 30.07.2024 21:26

@Raildex: Приятно знать. Очевидно, мой ответ был всего лишь предположением. Мы не знаем, какие заголовки и в каком порядке включены в ваш исходный код. Так что реальная проблема может быть похожей.

cremno 30.07.2024 21:37

(полагаться на порядок заголовков довольно глупо, если честно)

Raildex 30.07.2024 21:38

Другие вопросы по теме