Почему структуры должны быть сказаны, насколько большой они?

Я заметил, что в c/c ++ много Win32 структуры API должны быть сказаны, насколько большой они. т.е. someStruct.pbFormat = sizeof(SomeStruct)

Почему имеет место это? Это только по причинам прежней версии? Также какая-либо идея, что обозначает "свинец" также?

Править: ой, да я имел в виду "cbFormat"

8
задан GameTrainersWTF 31 May 2010 в 01:36
поделиться

5 ответов

Это необходимо для обратной совместимости при расширении Windows API.

Представьте себе следующие объявления

struct WinData
{
   long flags;
}
BOOL GetWinData(WinData * wd);

, которые вы вызываете следующим образом:

WinData wd;
GetWinData(&wd);

В будущей версии ОС это может быть расширено до

struct WinData
{
   long flags;
   long extraData;
}

Однако, если вы скомпилировали «старый» SDK, GetWinData не имеет возможности выяснить, что вы не знаете о extraData . Если он все равно заполнит его, он перезапишет данные в стеке. БУМ!

Вот почему в структуру добавляется «размер, известный вызывающей стороне», а в конце добавляются новые члены. Реализация GetWinData может проверить размер и решить, что «этот бедняга еще не знает обо всех новых функциях».

12
ответ дан 5 December 2019 в 07:33
поделиться

pb является примером венгерской нотации, по сути, схемы кодирования типа переменной в ее имени.

1
ответ дан 5 December 2019 в 07:33
поделиться

Чтобы будущие версии могли добавлять дополнительные поля и при этом обеспечивать обратную бинарную совместимость:

// CAUTION - the code is not 100% accurate and can fail due to packing rules.
// For illustrative purposes only
if (offsetof(struct foo, field) > f->pbFormat)
{
   // called with a version that predates the addition of
   // field so revert to a default value
}
0
ответ дан 5 December 2019 в 07:33
поделиться

Поскольку Win32 API - это C API, а не C ++, поэтому объектно-ориентированные методы расширения API недоступны. В C ++ API новая функция будет использовать структуру, унаследованную от старой, и вызывать интерфейс, который принимает базовую структуру, обеспечивая безопасность типов.

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

1
ответ дан 5 December 2019 в 07:33
поделиться

Это сделано для того, чтобы структура могла быть расширена в будущих версиях API, и тогда Windows могла знать (по размеру, который передал вызывающий объект), какие поля следует просматривать или нет. По сути, это грубая форма управления версиями API.

Обычно эти байты подсчета имеют префикс cb , что означает «количество байтов». Например, структура STARTUPINFO начинается с:

typedef struct _STARTUPINFO {
  DWORD  cb;
  LPTSTR lpReserved;
  ...
} STARTUPINFO, *LPSTARTUPINFO;

В какой-то момент она была расширена структурой STARTUPINFOEX , которая содержит ту же первую часть, но другого размера. В зависимости от значения cb Windows будет знать, следует ли смотреть на новое поле lpAttributeList .

8
ответ дан 5 December 2019 в 07:33
поделиться