【发布时间】:2010-05-31 01:11:22
【问题描述】:
我注意到在 c/c++ 中需要告诉许多 Win32 API 结构它们有多大。
即someStruct.pbFormat = sizeof(SomeStruct)
为什么会这样?仅仅是因为遗产的原因吗?也知道“pb”代表什么吗?
编辑:哎呀,是的,我的意思是“cbFormat”
【问题讨论】:
我注意到在 c/c++ 中需要告诉许多 Win32 API 结构它们有多大。
即someStruct.pbFormat = sizeof(SomeStruct)
为什么会这样?仅仅是因为遗产的原因吗?也知道“pb”代表什么吗?
编辑:哎呀,是的,我的意思是“cbFormat”
【问题讨论】:
这是为了在扩展 Windows API 时向后兼容。
想象以下声明
struct WinData
{
long flags;
}
BOOL GetWinData(WinData * wd);
你这样称呼它:
WinData wd;
GetWinData(&wd);
未来的操作系统版本可能会将其扩展到
struct WinData
{
long flags;
long extraData;
}
但是,如果您针对“较旧”的 SDK 进行编译,GetWinData 没有机会发现您不了解 extraData。如果它无论如何都会填充它,它将覆盖堆栈上的数据。轰!
这就是为什么将“调用者已知的大小”添加到结构中,并在末尾附加新成员的原因。 GetWinDataimplementation 可以检查大小并决定“这个可怜的家伙还不知道所有新功能”。
【讨论】:
这样可以在 API 的未来版本中扩展结构,然后 Windows 可以知道(通过调用者传入的大小)应该查看或不查看哪些字段。它基本上是 API 版本控制的一种粗略形式。
通常这些计数字节以cb 为前缀,代表“字节计数”。例如,STARTUPINFO 结构以:
typedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
...
} STARTUPINFO, *LPSTARTUPINFO;
这在某个时候使用STARTUPINFOEX 结构进行了扩展,该结构包含相同的第一部分但大小不同。根据cb 的值,Windows 将知道是否查看新的lpAttributeList 字段。
【讨论】:
pb 是Hungarian Notation 的一个示例,基本上是一种将变量类型编码为其名称的方案。
【讨论】:
因为 Win32 API 是 C API - 不是 C++,所以扩展 API 的面向对象的方法不可用。使用 C++ API 的新功能将使用从旧结构派生的结构并调用采用基本结构的接口,从而确保类型安全。
C 是一种过程语言,并且在您可以对结构执行的操作方面受到更多限制。
【讨论】:
这样未来的版本可以添加额外的字段并且仍然能够提供向后二进制兼容性:
// 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
}
【讨论】:
struct foo { int size; short s1; char c1; } 开始,然后将其扩展到 struct foo { int size; short s1; char c1; char c2; } 两者的大小都为 8,因此您将无法判断调用者是否具有带或不带字段 c2 的定义。
struct foo 版本 2 的有效方法。第一个 DWORD,设置为 sizeof(object),在 v1 和 v2 之间必须不同。