Предварительный вопрос как правильно интерпретировать этот 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.
typedef struct tWAVEFORMATEX {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
какой код? Я спрашиваю, почему _STATIC_ASSERT(sizeof(WAVEFORMATEX) == 18);
в принципе терпит неудачу.
Покажите, пожалуйста, структуру WAVEFORMATEX
. Вероятно, требуется 4-байтовое выравнивание.
Например. если первый член требует выравнивания по 4 байта, то это требуется для всей структуры, поэтому в конце будет дополнение.
WORD
имеет размер 4 байта, поэтому структура требует выравнивания 4.
@Barmar Learn.microsoft.com/en-us/cpp/build/reference/… Прочтите предупреждение. Я не уточняю /Zp
. WAVEFORMATEX — это структура Win32, поэтому я не могу изменить ее выравнивание.
Извините, меня смутили размеры WORD и DWORD.
Поскольку вы не используете эту опцию, она не упаковывает структуру, а это означает, что для выравнивания необходимо добавить отступы.
Об этом сообщает простая программа MSVC (64-бит) 18
.
...но если я определю внешне идентичное struct
, его размер будет 20
. Я не вижу никакой подсказки в mmeapi.h
.
@WeatherVane, только если вы перезапишете естественную упаковку. Должно быть 20 байт
@RbMm Нет, и я не понимаю, где mmeapi.h
это делает.
...и определение заключено в #ifndef _WAVEFORMATEX_
, поэтому оно должно быть определено в windows.h
. Когда я опускаю #include <mmeapi.h>
, программа все равно компилируется и запускается.
@WeatherVane: Заголовки Windows обычно содержат <pshpack1.h>
. Возможно, это связано с проблемой, с которой сталкивается ОП. Существует множество заголовков, которые не следует включать напрямую и, вероятно, в них отсутствует эта директива.
@cremno да, Windows.h
довольно маленький и включает в себя кучу других заголовков.
@WeatherVane: В документации WAVEFORMATEX даже сказано, что вам нужно включать mmeapi.h
, а не Mmreg.h
там, где фактически определена структура. Очень вероятно, что проблема в этом.
@cremno Mmreg.h
делает #include "pshpack1.h"
. Ни то, ни другое включать не нужно, только Windows.h
.
@WeatherVane, я не могу увидеть, где твоя ошибка, но #include <mmeapi.h >
и C_ASSERT(sizeof(WAVEFORMATEX)==20);
@RbMm какая ошибка? Размер 18
.
@WeatherVane, конечно, размер должен быть 20, а не 18.
@RbMm размер 18
, как показывает небольшая тестовая программа, независимо от того, #include <mmeapi.h>
я или нет, в этом нет необходимости.
@WeatherVane #include <mmreg.h >
использует #pragma pack(push,1)
и размер 18, если #include <mmeapi.h >
пакет не перезаписывается и размер 20
внутри mmreg.h
существуют #include "pshpack1.h"
в начале и #include "poppack.h"
в конце
@RbMm, ты не можешь просто включить mmreg.h
, не включая сначала Windows.h
. И если вы это сделаете, вам не нужно будет включать какой-либо другой заголовок Windows. Я не понимаю, к чему вы это ведете. Пользователь cremno уже размещал подобную информацию. Что вы добавляете?
@WeatherVane - конечно, я тоже включаю windows.h
раньше, но здесь это не имеет отношения.
Почему моя система сообщает
sizeof(WAVEFORMATEX) = 20
?
Компилятор предназначен для выравнивания членов DWORD
по четырем байтам. Если структура начинается с четырехбайтовой границы, все члены в ней будут выровнены так, как задумано компилятором: члены WORD
будут выровнены как минимум по двум байтам, а члены DWORD
будут как минимум по четырем байтам. выровнено. Это не будет справедливо для членов DWORD
, если структура начинается с границы, не кратной четырем байтам.
Если длина структуры составляла 18 байт и был объявлен их массив, то два соседних элемента в массиве не могли оба начинаться с четырехбайтовых границ. Поэтому компилятор добавляет два байта заполнения в конец массива, чтобы размер структуры составил 20 байт.
Нужно ли указывать упаковку, когда я хочу взаимодействовать с API WIn32? Я сомневаюсь, что мне нужно изменить выравнивание
@Raildex Win32 API ожидает 8-байтовое выравнивание во всех структурах API. Какую структуру структуры ожидают заголовочные файлы Windows SDK? /Zp8
@Raildex тебе не нужен. при естественном (не перезаписанном) выравнивании все будет ок. эта структура имеет размер 4 байта и размер 20 байт. размер всегда несколько выравнивается
@RemyLebeau, конечно, не 8-байтовое выравнивание для всех структур API. как пример WAVEFORMATEX
выровнено только 4 байта. wiapi ждет естественного выравнивания, если оно не специально перезаписано пакетом #pragma и __declspec(align)
Скорее всего, вы включили неправильный заголовок для 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: Приятно знать. Очевидно, мой ответ был всего лишь предположением. Мы не знаем, какие заголовки и в каком порядке включены в ваш исходный код. Так что реальная проблема может быть похожей.
(полагаться на порядок заголовков довольно глупо, если честно)
Пожалуйста, поместите сюда соответствующий код.