【问题标题】:Why does the WinAPI use an int (32 bits) for the BOOL type?为什么 WinAPI 对 BOOL 类型使用 int(32 位)?
【发布时间】:2012-06-23 04:22:53
【问题描述】:
// <windef.h>

typedef int                 BOOL;

因为 int 是 32 位,这不是浪费内存吗?

以防万一我错了,我尝试将普通的 bool* 发送到需要 BOOL* 的函数,直到我使用 typedef int 才起作用。

【问题讨论】:

  • 曾几何时,bool 不是 C 类型。见stackoverflow.com/questions/1608318/is-bool-a-native-c-type
  • 阿曼我很笨,我真的很笨
  • 你知道那个 typedef 已经存在多久了吗?
  • @luskan 永远不要这样做。当程序将您的 -1 解释为 TRUE 时,习惯了 1/0 的 sane BOOL 的人会被彻底搞砸。如果您必须这样做,请使用不同的名称,并将其设为枚举。
  • @JonathonReinhart Pfft。我似乎他们一直在 thedailywtf.com 上这样做。以有用的 FILE_NOT_FOUND 案例为例... ;-) 但实际上,一些 WinAPI(或者它只是 VB6?)使用我认为的 troolean...?

标签: c++ windows winapi boolean int


【解决方案1】:

哇,慢一点。首先,我很确定自从开始在 x86 上编程以来,程序员一直在使用 4 字节 ints 作为布尔变量。 (过去没有bool 数据类型之类的东西)。我敢猜测 Windows 3.1 &lt;Windows.h&gt; 中也有同样的 typedef。

其次,您需要更多地了解架构。您有一台 32 位机器,这意味着所有 CPU 寄存器都是 4 字节或 32 位宽。因此,对于大多数内存访问,存储和访问 4 字节值比存储和访问 1 字节值更有效

如果您将四个 1 字节布尔变量打包到一个 4 字节内存块中,则其中三个不是 DWORD(4 字节)对齐的。这意味着 CPU / 内存控制器实际上必须做更多工作才能获得价值。

在你因为制作那个“浪费”的 typedef 而抨击 MS 之前。考虑一下:在底层,大多数编译器(可能)仍然bool 数据类型实现为 4 字节 int,原因与我刚才提到的相同。在 gcc 中尝试一下,并查看地图文件。我敢打赌我是对的。

【讨论】:

  • 这个,1 字节的对齐问题对于标准大小的寄存器来说是可怕的。
  • 不过,在 x86 上,获得 1 字节和获得 4 字节一样容易。当您拥有多字节值时,对齐问题就会发挥作用。主要的低效率是您正在读取 4 个字节,而 1 会这样做......但无论哪种方式都需要相同的时间。
  • 历史参数有效,其余无效。 GCC 产生一个 1 字节的布尔值。加载/存储 1 个字节在芯片级别肯定是不同的,并且对缓存、对齐和并发性的影响与加载 4 个字节不同。
【解决方案2】:

首先,系统 API 中使用的类型必须尽可能与语言无关,因为该 API 将被多种编程语言使用。出于这个原因,任何在某些语言中可能不存在或在其他语言中可能以不同方式实现的“概念”类型都是毫无疑问的。例如,bool 就属于该类别。最重要的是,在系统 API 中,将接口类型的数量保持在最低限度是一个非常好的主意。任何可以用int 表示的东西都应该用int 表示。

其次,您关于这是“浪费内存”的断言毫无意义。为了成为“内存浪费”,必须构建一个包含大量BOOL 元素的聚合数据类型。 Windows API 不使用此类数据类型。如果您在程序中构建了这种浪费的数据类型,那实际上是您的错。同时,Windows API 不会以任何方式强制您将布尔值存储为 BOOL 类型。您可以为此目的使用字节甚至位。换句话说,BOOL 是一个纯粹的 interface 类型。 BOOLtype 的对象通常不会占用任何长时记忆,如果你使用得当的话。

【讨论】:

  • @DyP:不是真的。 AFAIK 现有的语言根本不支持 1 字节类型,因为它们没有理由这样做。
  • 我还是很喜欢你解释这个的方式。我们处理的是 API,而不是数据结构。
【解决方案3】:

处理器是 32 位的,当它在零整数上运行时有一个特殊的标志,这使得对 32 位布尔值的测试非常、非常、非常快。

测试一个 1 位或一个字节的布尔值会慢很多倍。

如果您担心内存空间,那么您可能会担心 4 字节布尔变量。

然而,大多数程序员更担心性能,因此默认使用更快的 32 位 bool。

如果这让您感到困扰,您也许可以让您的编译器优化内存使用。

【讨论】:

  • @cHao 是的,但是您必须做更多的工作才能从内存中获取该字节。您需要提取至少 32 位并对其进行屏蔽。
  • 更重要的是,如今大多数 x86 CPU —— 32 位的! -- 有 64 位数据总线(英特尔从 P6 开始就已经做到了,我相信...甚至可能是最初的 Pentium),所以屏蔽和/或移位仍然需要做。
【解决方案4】:

过去,BOOL 被用作 anything-not-0 = TRUE 类型。例如,一个对话过程返回一个BOOL,它可以携带很多信息。以下签名来自Microsoft's own documentation

BOOL CALLBACK DlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 

签名和函数结果混淆了几个问题,所以in the modern API改为

INT_PTR CALLBACK DialogProc(
    _In_  HWND hwndDlg,
    _In_  UINT uMsg,
    _In_  WPARAM wParam,
    _In_  LPARAM lParam
);

这个新奇的声明必须与旧声明保持兼容。这意味着INT_PTRBOOL 的大小必须相同。这意味着在 32 位编程中,BOOL 是 32 位。

一般来说,由于BOOL 可以是任何值,而不仅仅是 0 和 1,因此将 BOOLTRUE 进行比较是一个非常糟糕的主意。即使将其与FALSE 进行比较,这通常也是不好的做法,因为它很容易给人一种印象,即与TRUE 进行比较是可以的。另外,因为这完全没有必要。

顺便说一句,Windows API 中有更多布尔类型,特别是 VARIANT_BOOL,它是 16 位,其中逻辑 TRUE 表示为全 1 位模式,即 -1 作为有符号值...

这也是为什么直接与逻辑 FALSE 或 TRUE 比较不是一个好主意的另一个原因。

【讨论】:

    【解决方案5】:

    这里的大多数答案似乎都是错误的。对布尔值使用 4 个字节并不比使用 1 个字节快。 x86 架构读取 1 个字节的速度与读取 4 个字节的速度一样快,但 1 个字节的内存更少。对性能的最大威胁之一是内存使用。使用过多的内存,您将有更多的缓存未命中,并且您的程序会变慢。如果您只处理少数(数百个!)布尔值,这些东西并不重要,但如果您有大量的布尔值,使用更少的内存是提高性能的关键。在大型数组的情况下,我建议使用 1 位而不是 1 字节,因为如果可以节省 87% 的内存,那么屏蔽该位的额外逻辑是无关紧要的。您可以在标志位域中看到很多这种做法。

    这个问题的答案绝对只是“遗留原因”。也就是“不要碰没坏的东西”。更改一行代码(例如进行次要优化)可能会引入数百个没人愿意处理的其他问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 2020-10-29
      • 1970-01-01
      • 2010-11-13
      相关资源
      最近更新 更多