为什么在C++中char和bool类型大小相同?

35

我正在阅读《C++ 程序设计语言》。Stroustrup 在书中指出,sizeof(char) == 11 <= sizeof(bool),具体取决于实现。为什么布尔值这样简单的类型需要与 char 占用相同的空间呢?


2
它们不是“相同大小”。像其他类型一样,bool 必须至少与 char 相同大小。但它可以更大。 - underscore_d
7个回答

69

在现代计算机架构中,一个字节是最小可寻址的内存单元。要将多个位打包成一个字节需要应用额外的位移操作。在编译器级别上,这是内存与速度需求之间的权衡(在高性能软件中,那些额外的位移操作可能会累加并使应用程序不必要地减慢)。


23

因为在C++中,您可以取布尔值的地址,而大多数机器无法寻址单个位。


真的,但你可以通过重载一元&运算符并返回代理引用类来伪造它 :-P - Evan Teran
4
所谓的“伪指针”不能表示为char,因为C++标准要求将指向内置类型(不包括指向函数和成员的指针)的指针表示为char。因此,虽然对于用户定义的类型来说这个技巧很有用,但编译器无法将其用于bool类型。 - Steve Jessop
这是正确的答案。更有趣的问题是,为什么标准的作者们不愿意承认可能存在一个独立的“位”类型,其地址无法被获取,特别是它确实在结构体中识别了这种类型的概念(使用位域),而且自从这种类型在嵌入式C世界中已经被使用了很长时间。并非所有的链接器都支持比一个字节更细的粒度,但标准可以允许编译器在方便的情况下按位分配“位”变量,而不需要在任何情况下都这样做。 - supercat

12

它占用相同的空间,因为在内存中,你可以写入的最小空间是一个字节。这两个值都存储在一个字节中。虽然理论上只需要1个比特来表示布尔值,但你仍然需要一个完整的字节来存储该值。


5
理论上,bool 只需要一个比特位,但是使用少于 1 字节的数据会很混乱。您需要更多指令才能实现任何操作,并且没有真正的好处。
如果您想将多个 bool 压缩到单个字节中,可以使用 位域结构

但是最好不要这样做。 - Jonathan Leffler

3
一个字节是内存中最小的可寻址单元。
考虑以下代码:
    bool b[9];
    bool *pb0 = &b[0];
    bool *pb1 = &b[1];

    for (int counter=0; counter<9; ++counter)
    {
         // some code here to fill b with values
         b[counter] = true;

    }

如果将bool存储为1位,则pb0将等于pb1,因为它们具有相同的地址。显然,这是不可取的!
此外,在循环中的赋值将导致非平凡汇编代码。每次迭代循环都会涉及不同的位移操作。在高性能软件中,这些额外的位移操作可能会不必要地减慢应用程序。
STL库提供了一种解决方案,适用于空间确实很重要的情况。使用std::vector<bool>将bool存储为1位。上述例子的悖论不适用于该方法,因为
- operator[]的重载隐藏了位移操作的严格性 - 使用迭代器而不是指针可以使实现更加灵活

2

实际上,据我所知,在大多数实现中sizeof(bool) == sizeof(int)。 "int"旨在成为CPU最有效地处理的数据大小。因此,像"char"这样没有特定大小的东西与int的大小相同。如果每个对象有大量这些元素,您可能需要实现一种存储它们的打包方式,但在正常计算期间,应该保留其本机大小。


如果您要使用布尔数组,请使用std::vector<bool>,它具有用于位向量的专门实现,每个元素仅使用一个比特。 - Mats Fredriksson
@mats:std::bitset 比较稳定。vector<bool> 尝试成为 STL 容器,但失败了。此外还有 boost::dynamic_bitset,与 std::bitset 不同的是它可以增长。 - Steve Jessop

2
在C++中有一个叫做vector的东西,它试图利用理论上可以在一个char中存储8个bool的事实,但它被C++标准委员会普遍认为是一个错误。《effective stl》这本书实际上说“不要使用它”。这应该让你明白它有多棘手。
顺便说一下:Knuth有一本专门讲位运算的。Boost也有一个专门处理大量位数以更节省内存的方式。

你的意思是“被称为向量 **<bool>**”。其他类型的 vector 都是完全合理的。 - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接