2865 字
14 分钟
C 语言花了 52 年才把 bool 变成关键字?

1. 蛮荒时代:为了一个字节,可以不要命#

1972年,新泽西,贝尔实验室(Bell Labs)。

窗外的樱花也许开了,但丹尼斯·里奇(Dennis Ritchie)没空看。他正窝在一台 PDP-11/20 前面,这台机器的内存只有 24KB,硬盘比今天的智能手表还小。此时的 Unix 还是个用汇编语言写的“丑小鸭”,里奇的任务是把它变成天鹅——用一种高级语言重写,让它能跑在任何机器上。

他给自己定了一个近乎残酷的目标:

“这门语言生成的汇编代码,必须和手写的一样快、一样小。哪怕只多一个字节,都是对硬件的亵渎。”

于是,C 语言诞生了。

那是个连“函数原型”都没有的草莽时代。

那是个你写 int flag,然后直接写 if (flag = 1),编译器连个警告屁都不会放的时代。

那是个程序员人均自封硬件通、喝着咖啡、用纸带打孔的时代。

在他们眼里,布尔值?那不就是 0 和 1 吗?CPU 的 JZ(Jump if Zero)指令只认零和非零,你要什么布尔类型?

  • 多定义一个类型?浪费编译器内存。
  • 多一次类型转换?浪费 CPU 周期。
  • 这就是谋杀。

1973年,Unix 用 C 重写了 90%,内核仅 9000 行,运行内存不到 50KB。里奇和汤普森(Ken Thompson)把这事当战绩到处吹:“IBM 的系统要几兆内存,我们只要 50KB!”

在这种“谁更省谁是爹”的极客氛围里,谁敢提 “我想要一个 bool 类型”,下一秒就会被同事用看弱智的眼神围观。

2. 诸侯割据:混乱的巴别塔#

1978年,《The C Programming Language》(K&R 圣经)出版。这本蓝色小书给全行业下了一道“圣旨”:

“There is no need for a separate Boolean type.”

翻译过来就是:布尔值?不存在的。能用 int 解决的事,永远不要增加新类型。那时候程序员圈子小,大多是搞系统开发的硬核玩家。写汇编出身的人,对 “用42当true” 这种事不仅不觉得怪,反而觉得灵活。

1980年代初,C 语言开始统治嵌入式领域。 这种“灵活”开始显露獠牙。某汽车电子厂商的工程师直接用 speed > 3000 的返回值做判断。结果某次传感器故障返回 -1(非0),程序判定为“真”,测试车差点原地起飞。工程师拍着大腿笑:“还好 C 够野,换别的语言早崩了。”

1983年,微软用 C 写 DOS 和 Windows。 程序员们发现用 int 代替 bool 在大型项目里简直是灾难。微软的解决方案简单粗暴——自立门户:

typedef int BOOL;
#define TRUE 1
#define FALSE 0

这边微软刚搞出私有标准,那边 Unix 阵营也没闲着。

  • Linux (早期):Linus Torvalds 微软的BOOL太冗余,直接在头文件写 #define true 1
  • Motorola:开发包里叫 BOOLEAN
  • Texas Instruments:开发工具里叫 Bool。 大小写、拼写全不统一。

1987年,一场血案让矛盾爆发。 某银行将 Windows 代码移植到 Unix。

  • Windows 的 BOOLint (4字节)。
  • Unix 的 Bool 被定义成了 char (1字节)。

数据传输时,4字节的 TRUE (0x00000001) 没问题;但一个错误码 0x000000FF,在 Windows 端是非零(真),到了 Unix 端被截断成 0(假)。 结果:100 多笔交易记录凭空消失。

程序员对着日志骂了三天三夜,行业内终于响起了一个声音:“求求了,给 C 一个标准的 bool 吧。”

3. 第一次妥协:C89 的冷漠与 C99 的尴尬#

1989年,ANSI C (C89) 标准化会议。 “是否加入 bool” 成了核心议题。

  • 支持派:“现在代码量几十万行了,再用 int 当 bool 就是挖坑!”
  • 反对派(嵌入式大佬):“我们 1979 年写的核电站控制代码全是 flag = 5 代表 True,改了谁负责?”

更关键的是,当时C语言的“极简神话”还没破,不少老专家坚持 “C是给聪明人设的语言,不需要给新手做保姆式设计” 的观点。有位参与过 Unix 开发的老工程师放话:“当年用汇编写 Unix 的时候,连 int 都没有,不照样搞定?现在的年轻人就是娇气。”

最终,“暂不加入” 以微弱优势胜出。C89 标准里只冷冷地丢下一句:“用整数类型表示布尔值时,0为假,非0为真。”

标准发布后,某技术杂志的评论很扎心:“C语言的灵活,本质是把所有风险都丢给了使用者。”

1990年,C++ 崛起,1990年 C++ 标准草案里明确加入了 bool 类型,Bjarne Stroustrup(C++之父)在演讲里直言:“C的类型系统太松散,bool 是给代码加的安全锁。” 这一下,跨语言开发的矛盾爆发了 —— C 代码里的 int flag=2 传给 C++ 函数,C++ 直接判定为 true,但程序员本意可能是“2代表某种状态”,不是逻辑真。

1995年,Java 诞生,自带 boolean 类型。C++ 有 bool,Java 有 boolean。夹在中间的 C 程序员快疯了:同一个团队里,C++ 开发者用 bool,Java 开发者用 boolean,就 C 开发者抱着 int 死撑,代码评审时光解释“为什么用 3 当t rue”就要花十分钟。

1998年,C++98 标准正式发布,bool 成了和 int 平级的关键字。与此同时,互联网行业爆发式增长,十万行、百万行的 C 语言商业代码遍地都是——用 int 当 bool 导致的 bug 越来越离谱:电商网站的库存判断,因为库存=-1(缺货)被当成 true,显示有货;通信设备的状态监控,信号强度 = 0(无信号)被当成 false,跳过了告警逻辑。

1999年,C 标准委员会终于坐不住了。 但在 C99 的会议上,尴尬的一幕发生了。有人提议:“像 C++ 一样,干脆把 booltruefalse 设为关键字吧,像 C++ 那样。” 全场死寂。

一位来自老牌嵌入式厂商的代表慢悠悠举手:“不好意思,我们有 300 万行遗留代码,里面把 bool 当变量名用了上千次。如果它变成关键字,明天我们整个产品线就全编译不过了。”

另一位来自电信巨头的代表补刀: “我们也有 200 万行代码,宏定义里写了 #define bool int,改关键字等于让我们重写历史。”

最后一位头发花白、曾经参与过 ANSI C89 的老专家叹了口气,说了一句让全场沉默的话: “当年我们为了省一个字节没加 bool,今天要为这一个字节赔上整个生态。”

最终,C 语言做出了历史上最“体面”却也最别扭的投降 —— <stdbool.h>

  1. 新增一个底层类型 _Bool(为了不和旧代码冲突,名字起得像个下划线怪胎)。
  2. 提供一个可选头文件 <stdbool.h>,里面把 bool 宏定义为 _Bool

意思很明确:“你爱用就 include,不用就继续过你的 int 生活,谁也别得罪。”

4. 黎明前的黑暗:最社死的十年#

C99 之后,是 C 程序员最分裂的时代。

  • Google:内部代码规范里直接写死: “禁止在 C 代码中使用 bool,全部用 int,理由是历史代码太多,统一好维护。”这条反C99的规范,硬生生执行到2018年才删除。

  • Apple (Objective-C): 苹果在 Foundation 框架里定义了一行让跨语言开发者破防的代码:

    typedef signed char BOOL; // 定义 YES = 1, NO = 0

    这意味着 -1、255 这些在 C 里算“真”的值,到了 Objective-C 里依然是 YES,但存储时会被当成 1 字节的 signed char 处理。

    这下彻底乱了套:C 的 bool 是 _Bool 宏(通常1字节),C++ 的 bool 是原生类型(固定1字节),Objective-C 的 BOOL 是 signed char(1字节但符号位敏感)。有开发者做过测试:把C代码里的 bool flag = 255; 传给 Objective-C 函数,C 里判定为真,Objective-C 里因 255 超出 signed char 范围(-128~127),被解析为 -1,照样判定为 YES;但把Objective-C 的 BOOL 值(-1)传回 C++,C++ 会把 -1 当成 int 转成 bool,依然是 true。看似结果一致,但调试时变量内存值完全对不上,跨语言接口排错能让人熬三个通宵。

时间一晃到了 2011 年,C11 标准发布,有人提议把 bool 扶正成关键字,结果刚提出来就被否决了。这时候全球在用的 C 代码早以亿行计,当年那 300 万行嵌入式代码可能还在某工厂的设备里跑着,谁都不敢动这个雷。C11 能做的,只是在 C99 的基础上补了句“_Bool类型的取值只能是 0 或 1”,算是给这个半吊子类型加了层安全锁。

  • 新的编程语言像雨后春笋一样冒出来:每一家都在打 C 的脸

    Go(2009):原生 bool

    Rust(2015):bool 只有 true/false

    Swift(2014):连 Optional 都给你安排得明明白白

每出来一个新语言,C 程序员就要被教育一次: “看,人家连头文件都不用加。”

而 C 标准委员会,整整沉默了 25 年。

5. 最终救赎:C23 的迟到与和解#

2024年10月31日,C23 标准(ISO/IEC 9899:2024)正式发布。

此时,当年那些数百万行的旧代码,大多已随老旧设备退役。新生代开发者对“类型安全”的呼声终于盖过了“历史包袱”。

在 WG14 的会议室里,或许并没有痛哭流涕的道歉,但通过的决议却无声地宣告了一个时代的结束:

  1. 扶正booltruefalse 正式成为关键字。
  2. 兼容:如果代码里用 #define 提前定义过这些名字,编译器会优先使用用户定义,避免旧代码直接崩溃;
  3. 标准<stdbool.h> 不再是可选头文件,而是被纳入标准库的隐式依赖,哪怕不写 #include,也能直接用 bool 类型,彻底告别了加头文件才合规的尴尬。
  4. 规范:明确 sizeof(bool) 等于 1 字节,彻底解决了跨语言调用的对齐问题。

消息传出,有人在论坛晒出 C23 的测试代码:

bool success = (a == b);
if (success) { ... }

配文是:“活了半辈子,终于等到 C 有原生的 bool 了。”

尾声#

从 1972 到 2024,从 int_Bool 再到 bool。 这个关于 truefalse 的故事,本质上不是技术的演进,而是人类在“追求极致效率”与“不仅是机器,人也要读懂代码”之间的博弈。

C 语言从来不是最优雅的,但它是最懂生存法则的。 就像布尔值的本质永远是 0 和 1,C 语言的本质,永远是适配当下,兼容过往

这迟到了半个世纪的 bool,就是它给所有坚持到底的 C 程序员,最长情的告白。

文章内容改编自网络,侵权请联系删除

C 语言花了 52 年才把 bool 变成关键字?
https://yezi.press/posts/c-bool-history/
作者
Yezi 叶子
发布于
2025/11/23
许可协议
CC BY-NC-SA 4.0