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 的
BOOL是int(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++ 一样,干脆把 bool、true、false 设为关键字吧,像 C++ 那样。”
全场死寂。
一位来自老牌嵌入式厂商的代表慢悠悠举手:“不好意思,我们有 300 万行遗留代码,里面把 bool 当变量名用了上千次。如果它变成关键字,明天我们整个产品线就全编译不过了。”
另一位来自电信巨头的代表补刀: “我们也有 200 万行代码,宏定义里写了 #define bool int,改关键字等于让我们重写历史。”
最后一位头发花白、曾经参与过 ANSI C89 的老专家叹了口气,说了一句让全场沉默的话: “当年我们为了省一个字节没加 bool,今天要为这一个字节赔上整个生态。”
最终,C 语言做出了历史上最“体面”却也最别扭的投降 —— <stdbool.h>。
- 新增一个底层类型
_Bool(为了不和旧代码冲突,名字起得像个下划线怪胎)。 - 提供一个可选头文件
<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 的会议室里,或许并没有痛哭流涕的道歉,但通过的决议却无声地宣告了一个时代的结束:
- 扶正:
bool、true、false正式成为关键字。 - 兼容:如果代码里用
#define提前定义过这些名字,编译器会优先使用用户定义,避免旧代码直接崩溃; - 标准:
<stdbool.h>不再是可选头文件,而是被纳入标准库的隐式依赖,哪怕不写#include,也能直接用bool类型,彻底告别了加头文件才合规的尴尬。 - 规范:明确
sizeof(bool)等于 1 字节,彻底解决了跨语言调用的对齐问题。
消息传出,有人在论坛晒出 C23 的测试代码:
bool success = (a == b);if (success) { ... }配文是:“活了半辈子,终于等到 C 有原生的 bool 了。”
尾声
从 1972 到 2024,从 int 到 _Bool 再到 bool。
这个关于 true 和 false 的故事,本质上不是技术的演进,而是人类在“追求极致效率”与“不仅是机器,人也要读懂代码”之间的博弈。
C 语言从来不是最优雅的,但它是最懂生存法则的。 就像布尔值的本质永远是 0 和 1,C 语言的本质,永远是适配当下,兼容过往。
这迟到了半个世纪的 bool,就是它给所有坚持到底的 C 程序员,最长情的告白。
文章内容改编自网络,侵权请联系删除
陕公网安备61010302001363号