Почему структурам нужно сказать, насколько они велики? - PullRequest
8 голосов
/ 31 мая 2010

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

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

РЕДАКТИРОВАТЬ: упс, да, я имел в виду "cbFormat"

Ответы [ 5 ]

12 голосов
/ 31 мая 2010

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

Представьте себе следующие декларации

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

который вы называете так:

WinData wd;
GetWinData(&wd);

Будущая версия ОС может расширить это до

struct WinData
{
   long flags;
   long extraData;
}

Однако, если вы скомпилировали по «старому» SDK, GetWinData не сможет выяснить, что вы не знаете о extraData. Если бы он заполнил это независимо, он переписал бы данные в стеке. BOOOM!

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

8 голосов
/ 31 мая 2010

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

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

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

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

1 голос
/ 31 мая 2010

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

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

1 голос
/ 31 мая 2010

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

0 голосов
/ 31 мая 2010

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

// 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
}
...