如果你刚开始接触 Windows 编程,确实会遇到一些独特的编码风格和约定,这些可能会让你感到困惑。不过,一旦你熟悉了这些约定,它们实际上会帮助你更好地理解和使用 Windows API。Windows API 使用了许多自定义的数据类型,这些类型通常是为了提高代码的可移植性和可读性。Win32的命名约定采用匈牙利表示法。
匈牙利表示法
匈牙利表示法由 Charles Simonyi 提出,旨在通过前缀提供变量的 语义信息,即变量的用途或含义,这种表示法的目标是避免在错误的上下文中使用变量。
常见前缀示例:
前缀 | 含义 | 示例变量名 | 说明 |
---|---|---|---|
i | 索引(Index) | iRow | 表示行索引。 |
cb | 字节大小(Count of Bytes) | cbBuffer | 表示缓冲区的大小(以字节为单位)。 |
rw | 行号(Row) | rwPosition | 表示行号。 |
col | 列号(Column) | colPosition | 表示列号。 |
p | 指针(Pointer) | pBuffer | 表示指向缓冲区的指针。 |
sz | 以零结尾的字符串(String) | szName | 表示以 \0 结尾的字符串。 |
int iRow = 10; // 行索引
int cbBuffer = 1024; // 缓冲区大小(字节)
char* pBuffer = nullptr; // 指向缓冲区的指针
系统匈牙利表示法是匈牙利表示法的简化版本,主要关注变量的 类型信息。这种形式在 Windows API 和早期的 C/C++ 代码中非常常见。
前缀 | 类型 | 示例变量名 | 说明 |
---|---|---|---|
dw | DWORD(32 位无符号整数) | dwSize | 表示 32 位无符号整数。 |
w | WORD(16 位无符号整数) | wParam | 表示 16 位无符号整数。 |
b | BOOL(布尔值) | bFlag | 表示布尔值。 |
sz | 以零结尾的字符串(String) | szName | 表示以 \0 结尾的字符串。 |
h | 句柄(Handle) | hWnd | 表示窗口句柄。 |
p | 指针(Pointer) | pBuffer | 表示指针。 |
lp | 长指针(Long Pointer) | lpCmdLine | 表示长指针(现代系统中与普通指针相同)。 |
Typedef
Windows API 自定义数据类型的方式主要是通过 类型定义(typedef) 和 宏定义(macro) 来实现的。 其中许多是在头文件 WinDef.h
中定义的。
typedef
是 C/C++ 中的关键字,用于为现有类型定义一个新的别名。下面是后续学习时将经常遇到的一些数据类型。
整数类型
数据类型 | 大小 | 符号 |
---|---|---|
BYTE | 8 位 | 无符号 |
DWORD | 32 位 | 无符号 |
INT32 | 32 位 | 有符号 |
INT64 | 64 位 | 有符号 |
LONG | 32 位 | 有符号 |
LONGLONG | 64 位 | 有符号 |
UINT32 | 32 位 | 无符号 |
UINT64 | 64 位 | 无符号 |
ULONG | 32 位 | 无符号 |
ULONGLONG | 64 位 | 无符号 |
WORD | 16 位 | 无符号 |
此处列出的类型具有固定大小,32 位和 64 应用程序的大小相同。 例如, DWORD 类型始终为 32 位宽。
布尔类型
BOOL
是 Windows API 中定义的一个数据类型,用于表示布尔值(真或假)。
BOOL
是通过 typedef
定义的整数类型别名,通常是 int
或 long
。它在 Windows 头文件 WinDef.h
中定义如下:
同时头文件 WinDef.h
还定义用于 BOOL 的两个值。
#define FALSE 0
#define TRUE 1
但是,尽管定义 为 TRUE,但大多数返回 BOOL 类型的函数都可以返回任何非零值来指示布尔值,只有 FALSE
(0)明确表示假,而任何非零值(不一定是 TRUE
)都表示真。 因此,因此在判断 BOOL
值时,应避免直接与 TRUE
比较,而是检查它是否为 FALSE
。
正确的方式
// Right way.
if (SomeFunctionThatReturnsBoolean())
{
...
}
// or
if (SomeFunctionThatReturnsBoolean() != FALSE)
{
...
}
错误的方式
if (result == TRUE) // Wrong!
{
...
}
BOOL 是整数类型,不能与 C++ 的 bool 互换。这是因为BOOL
可以接受任何整数值,而不仅仅是 TRUE
(1)和 FALSE
(0),但是bool
只能接受 true
或 false
。如果将 BOOL
值直接赋值给 bool
变量,可能会导致意外的行为。例如:
BOOL b = 2; // b 是一个非零值,表示真
bool flag = b; // flag 会被赋值为 true(1),丢失了原始值(2)
指针类型
在 Windows API 中,指针类型的数据类型命名通常遵循一定的约定,使用前缀 P-
或 LP-
来表示指针类型。
前缀的含义
-
P-
:表示指针(Pointer)。 -
LP-
:表示长指针(Long Pointer)。这是从 16 位 Windows 时代遗留下来的命名习惯,当时有近指针(near
)和远指针(far
)的区别。在现代 32 位和 64 位系统中,LP-
和P-
实际上是等价的,但LP-
仍然被广泛使用以保持一致性。
示例
LPRECT
是指向 RECT
结构体的指针类型。RECT
是一个描述矩形的结构体,定义如下:
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
此时以下变量声明是等效的:
RECT* rect; // 指向 RECT 结构的指针
LPRECT rect; // 指向 RECT 结构的指针
PRECT rect; // 指向 RECT 结构的指针
指针精度类型
在 Windows 编程中,指针精度类型(Pointer-Precision Types)是一组特殊的数据类型,它们的大小始终与指针的大小相同。这意味着:
-
在 32 位应用程序中,这些类型是 32 位宽(4 字节)。
-
在 64 位应用程序中,这些类型是 64 位宽(8 字节)。
以下是常见的指针精度类型及其定义:
类型 | 描述 |
---|---|
DWORD_PTR | 无符号指针精度整数,用于表示指针大小的无符号整数。 |
INT_PTR | 有符号指针精度整数,用于表示指针大小的有符号整数。 |
LONG_PTR | 有符号指针精度整数,通常用于与 LONG 相关的指针运算。 |
ULONG_PTR | 无符号指针精度整数,通常用于与 ULONG 相关的指针运算。 |
UINT_PTR | 无符号指针精度整数,通常用于与 UINT 相关的指针运算。 |
这些类型在 Windows 头文件(如 basetsd.h
)中定义,通常是通过 typedef
实现的。相关源代码如下:
用途
①当需要将整数类型转换为指针类型时,使用指针精度类型可以避免精度丢失。
INT_PTR intPtr = 0x12345678;
void* pointer = reinterpret_cast<void*>(intPtr); // 将整数转换为指针
reinterpret_cast
用于在不相关的类型之间进行转换,例如将整数转换为指针,或将指针转换为整数
②指针运算在内存缓冲区中进行偏移操作
BYTE* buffer = (BYTE*)malloc(100); // 分配 100 字节的缓冲区
UINT_PTR offset = 50; // 偏移量
BYTE* newPointer = buffer + offset; // 指针运算
-
UINT_PTR
是一个指针精度的无符号整数类型,其大小与指针相同(32 位平台上为 32 位,64 位平台上为 64 位)。
-
buffer + offset
表示从buffer
指向的内存地址开始,向后偏移offset
个字节。
注意
C++ 核心准则(C++ Core Guidelines)建议避免使用匈牙利表示法(或其他类型编码的前缀表示法)Windows 团队在内部已经不再使用匈牙利表示法,但在示例和文档中仍然保留了它的用法。