cpp
数据模型和数据类型大小
C++数据类型的大小并不是完全固定的,而是由数据模型(Data Model)决定的- 不同的操作系统和编译器组合会采用不同的数据模型
为什么有不同数据模型
Windows选择LLP64是为了最大化32位代码兼容性- 保持
long为4字节避免破坏大量现有代码
- 保持
Unix系统历史上long就用于"机器字长"64位时自然扩展到8字节
数据类型大小规则
C++标准只规定了最小大小,而不是精确大小
|
1 2 3 4 5 6 7 8 9 |
sizeof(char) == 1 // 必须是 1 字节 sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) // 最小保证: char : 至少 8 位 short : 至少 16 位 int : 至少 16 位 long : 至少 32 位 long long : 至少 64 位(C++11) |
- 实际实现约束
|
1 2 3 4 5 |
// 通常的约束(但不是标准强制) sizeof(short) >= 2 sizeof(int) >= 2 sizeof(long) >= 4 sizeof(void*) == sizeof(size_t) // 指针大小等于地址总线宽度 |
数据模型对比1
WindowsWindows采用LLP64模型:Long Long and Pointer are 64-bit
| 类型 | 32位 Windows |
64位 Windows |
说明 |
char |
1 | 1 | 固定 |
short |
2 | 2 | 固定 |
int |
4 | 4 | 不变 |
long |
4 | 4 | 不变(重要!) |
long long |
8 | 8 | 固定 |
float |
4 | 4 | 固定 |
double |
8 | 8 | 固定 |
long double |
8 | 8 | 可能更大 |
void* |
4 | 8 | 变化 |
size_t |
4 | 8 | 变化 |
unix和linuxLinux/Unix采用LP64模型:Long and Pointer are 64-bit
| 类型 | 32位 Linux |
64位 Linux |
说明 |
char |
1 | 1 | 固定 |
short |
2 | 2 | 固定 |
int |
4 | 4 | 不变 |
long |
4 | 8 | 变化(关键差异!) |
long long |
8 | 8 | 固定 |
float |
4 | 4 | 固定 |
double |
8 | 8 | 固定 |
long double |
12/16 | 16 | 可能更大 |
void* |
4 | 8 | 变化 |
size_t |
4 | 8 | 变化 |
数据模型对比2
ILP32(32位系统标准模型)Int, Long, Pointer都是32位32位Windows、32位Linux、32位macOS
| 类型 | 字节数 |
int |
4 |
long |
4 |
pointer |
4 |
LP64(64位Unix标准模型)Long, Pointer是64位,Int保持32位64位Linux、64位macOS、大部分Unix系统
| 类型 | 字节数 |
int |
4 |
long |
8 |
pointer |
8 |
LLP64(64位Windows模型)Long Long, Pointer是64位,Long保持32位64位Windows
| 类型 | 字节数 |
int |
4 |
long |
4 |
long long |
8 |
pointer |
8 |
数据模型总结
32位系统(包括Windows、Linux、macOS、Unix)用的都是ILP32数据模型64位Linux、64位macOS、大部分64位Unix系统,用的都是LP64数据模型64位Windows用的是LLP64数据模型
LP和LLP对比
lplong64位8字节long double 32位12/16字节,64位16字节
llplong 64位4字节long double 32位8字节,64位8字节
数据类型大小总结
32位ilpint,long,ptr都是4字节long long 8字节windows:long double 8字节
linux:long double 12字节
64位lpint,long,ptr是4,8,8字节long long 8字节long double 16字节
64位llpint,long,ptr是4,4,8字节long long 8字节long double 8字节
数据类型跨平台推荐
- 使用固定宽度类型
|
1 2 3 4 5 6 7 8 9 10 11 |
#include <cstdint> int8_t // 固定 1 字节 int16_t // 固定 2 字节 int32_t // 固定 4 字节 int64_t // 固定 8 字节 uint8_t // 无符号版本 uint16_t uint32_t uint64_t |
windows
LPARAM 和 WPARAM
- 概述
LPARAM和WPARAM是Windows消息机制中的两个核心参数类型,用于在发送和处理窗口消息时传递附加信息
- 定义
|
1 2 3 |
// 在 Windows 头文件中的定义 typedef UINT_PTR WPARAM; // 无符号整型指针大小 typedef LONG_PTR LPARAM; // 有符号长整型指针大小 |
- 关于使用
- 这两个参数的具体含义完全取决于消息类型
Windows为不同的消息定义了不同的参数解释方式
- 用法1:简单传递数值
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// WM_COMMAND 消息 // WPARAM 的高字节:通知代码 // WPARAM 的低字节:控件ID // LPARAM:控件窗口句柄 case WM_COMMAND: { WORD notifyCode = HIWORD(wParam); // 高16位 WORD controlID = LOWORD(wParam); // 低16位 HWND hControl = (HWND)lParam; // 控件句柄 if (controlID == IDC_BUTTON1 && notifyCode == BN_CLICKED) { // 处理按钮点击 } break; } |
- 用法2:坐标信息
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// WM_MOUSEMOVE 消息 // WPARAM:按键状态标志 // LPARAM:鼠标坐标(x在低位,y在高位) case WM_MOUSEMOVE: { int xPos = GET_X_LPARAM(lParam); // 或 LOWORD(lParam) int yPos = GET_Y_LPARAM(lParam); // 或 HIWORD(lParam) WPARAM keyFlags = wParam; if (keyFlags & MK_LBUTTON) { // 左键按下时移动 } break; } |
- 用法3:传递指针
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// WM_COPYDATA 消息 // WPARAM:发送方窗口句柄 // LPARAM:指向 COPYDATASTRUCT 的指针 case WM_COPYDATA: { HWND hSender = (HWND)wParam; COPYDATASTRUCT* pCDS = (COPYDATASTRUCT*)lParam; // 处理接收到的数据 void* data = pCDS->lpData; DWORD dataSize = pCDS->cbData; break; } |
- 用法4:打包多个值
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// WM_SIZE 消息 // WPARAM:调整大小类型(SIZE_MAXIMIZED 等) // LPARAM:新的客户区尺寸 case WM_SIZE: { UINT sizeType = (UINT)wParam; int width = LOWORD(lParam); int height = HIWORD(lParam); if (sizeType == SIZE_MAXIMIZED) { // 窗口被最大化 } break; } |
相关宏
- 位操作
|
1 2 3 4 5 6 7 8 9 10 11 |
// 提取高低字节 WORD lowWord = LOWORD(param); // 低16位 WORD highWord = HIWORD(param); // 高16位 // 组合两个字节为一个值 LPARAM result = MAKELPARAM(low, high); WPARAM result = MAKEWPARAM(low, high); // 专门用于坐标 int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); |
- 类型转换
|
1 2 3 4 5 6 7 8 9 10 |
// 句柄转换 HWND hWnd = (HWND)lParam; HMENU hMenu = (HMENU)wParam; // 指针转换 MyStruct* pData = (MyStruct*)lParam; // 整数转换 int value = (int)wParam; UINT flags = (UINT)wParam; |
具体消息示例
WM_KEYDOWN / WM_KEYUP
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
case WM_KEYDOWN: { WPARAM virtualKey = wParam; // 虚拟键码(如 VK_RETURN) LPARAM keyData = lParam; // 键盘扫描码和其他信息 WORD repeatCount = LOWORD(lParam); // 重复次数 BYTE scanCode = LOBYTE(HIWORD(lParam)); // 扫描码 BOOL isExtended = (lParam & 0x01000000) != 0; // 扩展键 if (virtualKey == VK_ESCAPE) { // 处理ESC键 } break; } |
WM_HSCROLL / WM_VSCROLL
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
case WM_HSCROLL: { WORD scrollCode = LOWORD(wParam); // 滚动条操作码 WORD position = HIWORD(wParam); // 滚动框位置 HWND hScrollBar = (HWND)lParam; // 滚动条句柄 switch (scrollCode) { case SB_LINEUP: // 向上滚动一行 break; case SB_THUMBTRACK: // 拖动滚动框 break; } break; } |
WM_NOTIFY
|
1 2 3 4 5 6 7 8 9 10 |
case WM_NOTIFY: { UINT controlID = (UINT)wParam; NMHDR* pNMHDR = (NMHDR*)lParam; if (pNMHDR->code == NM_CLICK) { // 处理点击通知 } break; } |
自定义消息
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 定义自定义消息 #define WM_MY_MESSAGE (WM_USER + 1) // 发送自定义消息 SendMessage(hWnd, WM_MY_MESSAGE, (WPARAM)myValue, // 可以传递任何值 (LPARAM)myPointer); // 可以传递指针 // 处理自定义消息 case WM_MY_MESSAGE: { int value = (int)wParam; MyData* pData = (MyData*)lParam; // 自定义处理逻辑 break; } |
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ COM组件_303/07
- ♥ breakpad记述:Windows07/27
- ♥ WinDbg相关01/12
- ♥ Windows开发相关简记一08/15
- ♥ Windows 核心编程 _ 进程三06/19
- ♥ Dump分析:未捕获的异常,查看内存相关命令03/25