为什么 WinAPI 对 BOOL 类型使用 int(32 位)
Why does the WinAPI use an int (32 bits) for the BOOL type?
// <windef.h>
typedef int BOOL;
这不是浪费内存吗,因为 int 是 32 位?
以防万一我错了,我尝试将一个正常的bool*
发送到一个需要BOOL*
的函数,并且在我使用 typedef int 之前不起作用。
哇,慢一点。 首先,我很确定程序员自从在x86上编程开始以来就一直使用4字节int
作为布尔变量。(过去没有bool
数据类型这样的东西)。我冒昧地猜测,同样的typedef在Windows 3.1 <Windows.h>
中。
其次,您需要更多地了解架构。您有一台 32 位计算机,这意味着所有 CPU 寄存器都是 4 字节或 32 位宽。因此,对于大多数内存访问,存储和访问 4 字节值比存储和访问 1 字节值更有效。
如果将四个 1 字节布尔变量打包到一个 4 字节内存块中,则其中三个未对齐 DWORD(4 字节)。这意味着CPU/内存控制器实际上必须做更多的工作才能获得值。
在你砸 MS 制作那个"浪费"的类型定义之前。考虑一下:在引擎盖下,大多数编译器(可能)仍然将bool
数据类型实现为 4 字节int
,原因与我刚才提到的相同。在 gcc 中尝试一下,然后查看地图文件。我敢打赌我是对的。
首先,系统 API 中使用的类型必须尽可能独立于语言,因为该 API 将被多种编程语言使用。出于这个原因,任何可能在某些语言中不存在或可能在其他语言中以不同方式实现的"概念"类型都是毫无疑问的。例如,bool
属于该类别。最重要的是,在系统 API 中,将接口类型的数量保持在最低限度是一个非常好的主意。任何可以用int
表示的东西都应该用int
表示。
其次,你关于这是"浪费记忆"的断言是没有任何意义的。为了成为"浪费内存",必须构建一个涉及大量BOOL
元素的聚合数据类型。Windows API 不使用此类数据类型。如果你在程序中构建了这种浪费的数据类型,那实际上是你的错。同时,Windows API 不会以任何方式强制您将布尔值存储在BOOL
类型中。您可以使用字节甚至位来实现此目的。换句话说,BOOL
是一种纯粹的接口类型。如果您正确使用它,BOOL
类型的对象通常根本不占用任何长期记忆。
历史上BOOL
被用作 anything-not-0 = TRUE 类型。例如,对话框过程返回了一个BOOL
,该可以携带大量信息。以下签名来自Microsoft自己的文档:
BOOL CALLBACK DlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
签名和函数结果混淆了几个问题,因此在现代 API 中,它反而是
INT_PTR CALLBACK DialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
这一新奇的宣言必须与旧宣言保持兼容。这意味着INT_PTR
和BOOL
的大小必须相同。这意味着在 32 位编程中,BOOL
是 32 位。
通常,由于BOOL
可以是任何值,而不仅仅是 0 和 1,因此将BOOL
与 TRUE
进行比较是一个非常不好的主意。即使将其与FALSE
进行比较是有效的,这通常也是不好的做法,因为它很容易给人一种印象,即与TRUE
进行比较是可以的。另外,因为它是完全没有必要的。
顺便说一下,Windows API 中有更多的布尔类型,特别是 VARIANT_BOOL
它是 16 位,其中逻辑 TRUE 表示为所有 1 位模式,即 -1
作为有符号值...
这就是为什么直接与逻辑 FALSE 或 TRUE 进行比较不是一个好主意的另一个原因。
处理器是 32 位的,并且在零整数上运行时有一个特殊的标志,这使得测试 32 位布尔值非常、非常、非常快。
测试 1 位或 1 字节的布尔值会慢很多倍。
如果您担心内存空间,那么您可能会担心 4 字节布尔变量。
然而,大多数程序员更担心性能,因此默认使用更快的 32 位布尔值。
如果这困扰您,您也许可以让编译器针对内存使用情况进行优化。
这里的大多数答案似乎都被误导了。对布尔值使用 4 个字节并不比使用 1 个字节快。x86 体系结构可以读取 1 个字节的速度与读取 4 字节的速度一样快,但 1 个字节的内存更少。对性能的最大威胁之一是内存使用。使用太多内存,您将有更多的缓存未命中,并且您的程序速度会变慢。如果你只处理少量(数百个!)布尔值,这些东西并不重要,但如果你有大量的布尔值,使用更少的内存是提高性能的关键。对于大型数组,我建议使用 1 位而不是 1 个字节,因为如果它节省了 87% 的内存,那么屏蔽该位的额外逻辑是无关紧要的。您在标志位域中经常看到这种做法。
这个问题的答案绝对只是"遗留原因"。也就是说,"不要碰没有坏的东西。像更改小优化一样更改一行代码可能会引入数百个没有人愿意处理的其他问题。
- 为什么在全局范围内使用"extern int a"似乎不行?
- int(c) 和 c-'0' 之间的区别。C++
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 是否可以从int转换为enum类类型
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 'short int'持有的值溢出,但"自动"不会溢出?
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 调用'begin(int [n])'没有匹配函数
- 没有显式声明的int[]中的foreach
- 在c++中访问int到类对象的映射时出错
- 为什么我无法更改"set<set>"循环中的值<int>
- 长 长 int 不要 长 int 好
- C++程序在循环后给出奇怪的int值
- 如何计算数据类型的范围,例如int
- 为什么 WinAPI 对 BOOL 类型使用 int(32 位)
- 从Windows窗体外部(从int WINAPI WinMain)调用Windows窗体方法