C ++:为什么bool长8位?


132

在C ++中,我想知道为什么布尔类型是8位长(在我的系统上),其中只有一位足以容纳布尔值?

我曾经认为这是出于性能方面的考虑,但是在32位或64位机器上(寄存器为32或64位宽),性能优势是什么?

还是仅仅是这些“历史性”原因之一?


9
布尔不是我系统上的8位。它是4个字节,与int相同。
Brian Neal 2010年

21
上次有人认为您的想法时,我们以std :: vector <bool>结尾,这是有史以来最令人讨厌的stl“功能” =)
Viktor Sehr 2010年

1
jldupont,我想你误解了我。我当时要求的系统sizeof(bool)应该是4。我可以保证msvc具有32位布尔值,但是我只是尝试了而没有。
avakar 2010年

7
公平地讲,问题vector<bool>不在于它试图变得聪明并且将bool打包成小块,而是试图做到这一点并伪装成STL容器。一个普通的位集就可以了,只要它也不会假装成STL容器即可。
jalf

2
@avakar-您可能会将C ++ bool数据类型与BOOL类型定义为的Windows 类型混淆long。因此sizeof(bool) != sizeof(BOOL),我确定会引起很多混乱(并且可能还有很多错误)。特别是因为Windows 中也有booleanBOOLEANtypedef,它们是的别名unsigned char。另外,请注意,虽然通常为bool1个字节,但C ++标准有一个注释,专门指出sizeof(bool)可以更大。
Michael Burr 2010年

Answers:


219

因为每种C ++数据类型都必须是可寻址的。

您将如何创建指向单个位的指针?你不能 但是您可以创建一个指向字节的指针。因此,C ++中的布尔值通常为字节大小。(它也可能更大。这取决于实现。主要是它必须是可寻址的,因此C ++数据类型不能小于一个字节)


7
“字节”寻址是一种体系结构选择(硬件级别):一个人可以很好地设计一个具有不同“寻址单元”的系统。对于普通处理器,无论如何寻址一个“字节”最终都会从外部存储器中获取多个“字节”:这是由于效率方面的原因。
jldupont 2010年

8
是的,这是一种硬件选择,如果硬件允许的话,布尔的大小可能会改变。但是OP询问为什么布尔值是8位宽,在这种情况下,通常是因为CPU只能寻址8位字节。
jalf

2
@jldupont:在某些系统中,指针地址的粒度比字节要细(我以前在旧的TI TMS34010 / 20上进行了编程,它使用了逐位指针),但是它们很少见。
迈克尔·科恩

1
不明白你的意思。每个对象都必须是可寻址的,也就是说,必须可以检索对象的地址。该对象不必存储自己的地址。一个字符通常为8位宽,足以存储256个字符中的任何一个,但是每个字符还有一个地址,该地址由其在内存中的位置定义。这就是为什么您可以创建一个指向char的指针的原因。
jalf

88
如果我可以做出一个狡猾的比喻:我的大楼有八层,但是邮局不承认它们是不同的地址。因此,如果我想给自己一个地址,那么即使我确实位于一楼,也必须租用整个建筑物。我没有使用其他七个楼层来“存储地址”,我只是因为邮局规定地址是指建筑物而不是楼层而被迫浪费了它们。C ++对象必须有自己的地址-交货后没有邮件室可以对邮件进行排序;-)
Steve Jessop 2010年

39

存储器是字节可寻址的。您不能对单个位进行寻址,而不会移位或屏蔽从内存中读取的字节。我想这是一个很大的原因。


1
不总是。例如,8051 MCU具有16字节的位可寻址位置
搁浅

20

boolean类型通常如下寻址存储器的最小单位的目标机器(即,通常的8位字节)的。

始终以“块”形式访问内存(多而言之,这是为了提高硬件级别和总线事务的效率):在大多数CPU系统中,布尔位不能被“单独”寻址。当然,一旦数据包含在寄存器中,通常会有专门的指令来独立地操作位。

因此,为了提高使用“布尔”基本数据类型的效率,通常使用“位打包”技术。诸如enum(C语言中)具有2编码能力的技术就是一个很好的例子。在大多数语言中都可以找到相同的技巧。

更新:由于进行了精彩的讨论,因此引起了我的注意,sizeof(char)==1根据C ++ 的定义。因此,“布尔”数据类型的寻址与可寻址内存的最小单位紧密相关(加强了我的观点)。


对于您留下的所有注释,令人印象深刻的是,您忽略了答案中最重要的部分:bool类型遵循可分配内存的最小单位,因为C ++要求必须有可能创建指向它的指针。没有该要求,bool即使在当前的字节寻址机器上,也可以将a表示为单个位。
jalf

1
嗯...我可以设计一个可以寻址的CPU体系结构...甚至可以为其编写编译器等。我可以有一个特殊的内存区域(或其他),可以“按位寻址”。并非没有想象力。
jldupont 2010年

2
是的,在该系统上,可以将布尔值设为一点。但是OP并没有问“为什么在jlduponts虚拟CPU上宽度为8位”。他询问了当前常用的日常CPU,在这些CPU上,这是因为它们是字节可寻址的。
jalf

4
在C ++中,每个定义的sizeof(char)== 1,因此您的硬件可以执行或不能执行的操作无关紧要。您不能有sizeof(bool)<sizeof(char)。BTW C ++的定义方式是,如果不方便使用最小的硬件可寻址单元,则可以使用“胖”指针来寻址硬件可以寻址的某些子单元。至少在某些C编译器中已将其用于旧字可寻址体系结构。
AProgrammer 2010年

@AProgrammer::sizeof(char)==1 definition这是对我观点的最好反驳。谢谢!
jldupont 2010年

6

关于8位是可寻址的最小内存量的答案是正确的。但是,某些语言某种程度上可以将1位用于布尔值。我似乎记得Pascal将集合实现为位字符串。也就是说,对于以下集合:

{1, 2, 5, 7}

您可能在内存中有这个:

01100101

当然,您可以根据需要在C / C ++中执行类似的操作。(如果您要跟踪一堆布尔值,这可能是有道理的,但这实际上取决于情况。)


8
实际上,C ++使用专门的容器vector <bool>来做到这一点-通常将其视为灾难。

C ++也使用从C继承的“位字段”来执行此操作。声明结构/类的成员变量时,可以声明用于存储值的位数(例如,“无符号短字段:3”)。

@Neil:为什么通常认为这是一场灾难?这是性能问题吗?
杰罗姆

2
@Jerome:这是因为,由于有一点是不可寻址的,所以它不能像常规的那样表现vector。它实际上不是STL类型的容器,因为对行为有约束。更糟糕的是,这会导致某人拥有bools并想要使其成为a vector的问题。这是令人惊讶的行为,这不是您想要的语言。
David Thornley,2010年

1
@jldupont-一次提出这样的观点就足够了。C ++不能保证位是可寻址的(而不是相反的),无论硬件有什么能力。

1

我知道这是旧的,但我认为我会投入2美分。

如果将布尔值或数据类型限制为一位,那么您的应用程序就有内存损坏的危险。如何处理只有一位的内存中的错误统计信息?

我去了一次求职面试,程序负责人对我说的一句话是:“当我们发送信号以发射导弹时,我们只是通过无线发送一个简单的开/关位。发送一位的速度非常快,我们需要该信号尽可能快。”

好吧,这是一次测试,以了解我是否了解概念以及位,字节和错误处理。一个坏家伙发出一点味精会多么容易。或者,如果在传输过程中该位以其他方式翻转,会发生什么情况。


新问题,不要将您的问题发布为其他问题的答案。
IgorJerosimić13年

6
我认为此“答案”中包含的问题实际上是一个花哨的问题,即我们之所以不将布尔值作为一位实现,是因为一位不能处理错误统计信息。
斯蒂芬·霍尔特

1
@StephenHolt,但这不是原因,并且TBH这个答案没有任何意义。
doc 2016年

1
...什么?我不知道您所说的“错误统计信息”是指CRC还是类似的东西,还是陷阱表示。但是无论如何,即使是较大的类型也不会使用其额外的“备用”位来表示“错误状态”,因为除极端环境编码器外,所有其他人都正确地假设其硬件可以在其代码读取内存之前对其进行错误检测/纠正,因此他们不必花时间以某种方式在每个变量上填充验证信息或其他内容。这不是为什么bool在OP的机器上使用8位,而在我的机器上使用32位的原因,因为其他7或31位肯定没有用于任何“错误统计”。这是没有意义的
underscore_d

1

一些嵌入式编译器具有int1类型,用于对布尔标志进行位打包(例如,用于Microchip MPU的CCS系列C编译器)。设置,清除和测试这些变量使用单指令位级指令,但是出于其他答案中指出的原因,编译器将不允许进行任何其他操作(例如,获取变量的地址)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.