ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

听故事学语言 · 第一章 让计算机说人话

听故事学语言 · 第一章 让计算机说人话 听故事学语言 · 第一章让计算机说人话本章讲述计算机的母语是什么样的人类如何一步步教会它类人的表达以及本书要学的 C 语言在这条进化线上站在哪。本章结束时将写下并运行人生中的第一个 C 程序。序章讲了 C 语言的出生故事贝尔实验室、一台没人要的 PDP-7、汤普逊的游戏、里奇给 B 加上类型。但那只是回答了这门语言从哪来。还有一个更基本的问题没有回答计算机原本根本不会说话。它只认识电平的高与低。让一台由开关组成的机器理解人类的表达这件事是怎么做到的本章讲这条时间线。C 语言在这条时间线上的位置决定了它的每一个语法为什么是今天这个样子。一、计算机的母语0 和 1计算机的基本元件是无数个微小的开关今天它们叫晶体管一颗芯片里有上百亿个。开关只有两种状态通或断。工程师用 1 表示通、0 表示断——于是计算机的一切信息数字、文字、图片、声音在它内部全部是 0 和 1 的组合。这便是机器语言计算机唯一能直接听懂的语言也是它的母语它不是为人类设计的。用机器语言写程序是什么样子是一行行这样的东西01101000 01101001而一个真正能用的程序是几千行这样的东西。二十世纪四十年代末五十年代初世界上最早的程序员们就是这样工作的把程序写成一张张打孔卡片——纸卡上打孔的位置代表 1没打孔的位置代表 0一张卡片一行代码一个程序动辄几千张卡。打孔卡本身的历史比计算机更早。1890 年美国人口普查首次使用了工程师赫尔曼·何乐礼Herman Hollerith发明的打孔卡制表机把原本需要八年的统计工作压缩到一年——他创办的公司后来几经合并成了 IBM。打孔卡固定为每张 80 列这个80 列的尺寸在此后一个世纪里悄悄规定了终端屏幕的宽度、命令行的长度甚至今天许多代码编辑器里的那条换行参考线。这条传播链的细节学界仍有梳理但 80 列的传统源自打孔卡是公认的。那个年代的程序员怀里抱着装满卡片的盒子排队上机。盒子一旦摔在地上几千张卡片散落一地好在卡片角上印有序列号可以重新排序。这就是那个时代程序员最恐惧的事故。用 0 和 1 与机器对话准确、忠实但有两个致命的问题人写不动人也读不懂。二、人类的第一次反击汇编第一个改变是把 0 和 1 换成单词。工程师们注意到机器指令里有相当一部分是重复的操作比如把数据从一处搬到另一处、做一次加法、比较两个数。既然每一种 0 和 1 的组合对应一个固定操作那为什么不让人类用简短的单词来写再由一个程序把单词自动翻译回 0 和 1于是有了助记符mnemonic帮助记忆的符号。搬运用 MOVmove移动加法用 ADDadd加法。写程序变成了这样MOV A, 3 ADD A, 5把助记符翻译成机器语言的程序称为汇编器assembler它是人类历史上第一个翻译程序。今天一切编程语言的鼻祖身份都属于它。这是人类的第一次反击不再迁就机器的母语而是让机器适应一点人类的习惯。但汇编语言的局限依然刺眼。第一它和机器型号死绑在一起为一种处理器写的汇编程序换一种处理器就要全部重写第二它仍然一句对应一条机器指令程序员依然在用机器的方式思考一条显示一个字符的指令背后可能是十几行汇编。人类想要的是一种能直接表达逻辑的语言写一句如果……那么……写一句重复十次写完之后由翻译程序把它自动翻译成机器需要的任何形式。这样的语言后来被称为高级语言。而让高级语言成为可能的是翻译这个想法本身。三、高级语言把英语搬进编程机器不可能自动把人类的符号翻译成程序在二十世纪五十年代初这是行业内的共识。打破共识的是一位海军女性数学家格蕾丝·霍珀Grace Hopper。1952 年她的团队写出了历史上第一个编译器 A-0一个能把人类书写的类英语指令自动翻译成机器语言的程序。她后来回忆当初告诉同事们这个想法时得到的回应是计算机连英语都理解不了这是常识。霍珀的生平极富故事性她官至美国海军少将一艘驱逐舰以她的名字命名。编译器之母四个字说的就是她。1957 年IBM 在约翰·巴科斯John Backus的带领下发布了FortranFormula Translation公式翻译它是第一个被广泛使用的高级语言为科学计算而生。发布之前业界的主流判断是编译器生成的代码效率不可能与手写汇编相提并论。Fortran 的优化器用实测结果终结了这个判断。从这一刻起先写人类看得懂的语言再让机器翻译成为了主流工作方式。高级语言长得什么样看一行最典型的例子printf(Hello, World!\n);仔细看这不是天书这是压缩的英语printfprint打印 fformatted格式化合起来即格式化打印。include包含。main主要的。return返回。高级语言就是开发者把最常用的英语单词做了简化形成的一种类英语语言。开发者是美国人对他们而言用最熟悉的英语单词做关键字是最自然的选择写起来虽然仍比说英语麻烦但比 0 和 1 舒服一万倍。这里有一个值得深思的反例既然高级语言是对母语单词的简化那么中国的开发者有没有可能用汉语编程历史上确实存在过这样的尝试即 2000 年前后问世的易语言用完整的中文词汇作为关键字。想法很美好现实很残酷它始终未能得到推广。原因的第一层在物理层面上即键盘。今天通用键盘的 QWERTY 布局是为拉丁字母设计的序章讲过那个布局甚至都不是为快设计的只是历史偶然汉字无法直接键入需要额外的输入法环节。第二层在社区层面上一门编程语言的生命力在于它的社区、教程与工具链孤军奋战的语言留不住人。易语言的教训说明编程语言对英语的偏向不是英语更高级而是工具受制于物理载体生态锁死于起点。这同样是历史的遗留。四、AI 时代机器终于向人类走了过来把时间轴拉长会看到一条清晰的轨迹它叫人类与机器相向而行阶段语言形态谁向谁走了半步1940s机器语言0 和 1人类的母语全面让位1950s汇编助记符人类第一次反击但仍是机器的节奏1957高级语言类英语人类大幅靠近机器的表达2020s自然语言vibe coding用日常语言指挥 AI 编程机器向人类走了过来七十多年四个阶段方向从未变过让机器离人类越来越近。而 C 语言站在这条路的第三阶段它是类英语时代最成功的语言也是今天几乎所有主流语言C、Java、Python 的底层实现的祖先或基石。它的每一个不自然无论是分号、大括号还是类型声明、令人生畏的指针都不是设计者的刁难而是1972 年的人类所能向机器走到的最远处。理解了这一点再看这些语法目光会完全不同。序章里那三位老家伙造出的语言就这样站在了历史的关键位置上。而理解了这条进化线也就理解了本书的书名——听故事学语言学的正是让计算机说话的每一代故事。那么C 语言具体是怎么用的五、第一个程序从 1978 到今天先说在哪写。写 C 程序需要一个编译器编译器是什么马上讲到。市面上常见的选择有三类Dev-C竞赛圈的常用老牌工具Visual Studio工业界的重型武器功能全面但体量庞大本书使用的是内置了完整编译环境的编程工具无需安装任何额外软件代码写完直接点运行编译器已经内置在内。再说写什么。下面是本书的第一个完整程序每一行都标注了它在做什么以及其中每个英语单词的中文含义// #include 是包含的意思 // 把 stdio.h 这个文件搬进来 —— std standard标准i input输入o output输出 // 这个文件里装着 printf 等工具的说明书 #include stdio.h // main 是主要的意思程序的入口计算机从这里开始执行 // int 是 integer整数的缩写程序结束后会向操作系统报告一个整数 int main(void) { // printf print打印 fformatted格式化把括号里的内容显示到屏幕上 // \n 是换行符 —— n newline新行相当于按一次回车键 printf(Hello, World!\n); // return 是返回的意思把 0 交给操作系统 —— 0 代表一切正常 return 0; }在编程环境里键入这段代码点击运行。屏幕上会出现一行Hello, World!这就是人生第一个程序。按运行按钮之前屏幕上什么都没有按下之后计算机说了第一句话。这一秒值得停一下序章里说过一道题的答案印在纸上不算数跑出来的才算数从这一秒起自己按运行、自己看结果就是这门语言的学习方式。然后回答一个初学者的经典疑问为什么程序最后要写 return 0这个问题曾困扰包括教材编写者在内的几乎所有初学者。答案藏在历史里。1978 年的 KR 版本中上面这段程序可以写得更短main() { printf(hello, world\n); }没有 int没有 void没有 return 0。为什么今天的写法多了这么多字因为标准在演进。C 语言在 1989 年被美国国家标准协会ANSI正式标准化此后经历了 1999 年C99、2011 年C11等多次修订。每一次修订都在把当年编译器好心帮忙的默契变成白纸黑字的规则int 显式声明了函数返回类型void 明确了参数为空return 0 把成功的约定写了出来。每多出来的一个字都是一段标准演进的历史。各版本标准的具体条款差异见第十八章的完整梳理。而 return 0 本身还有第二层含义0 是程序交给操作系统的退出码0 表示一切正常其他数字代表各种出错的类型。程序并不是自说自话它在运行结束后要向操作系统交一份报告。这份报告的传统与 UNIX 同龄。最后是编译这个概念。写好的代码是给人看的文本计算机能执行的却是 0 和 1。从文本到可执行程序之间的翻译过程称为编译。如何理解编译一个准确的比喻它像翻译一整本英文书不是一句一句地翻而是整本地翻完、装订成册再交给读者。读者计算机拿到的是成品读起来飞快。Python 这样的语言则采用另一种方式一句一句地翻、一句一句地执行两种方式的差异会在后面的章节里反复出现。语法卡本章语法规则速查。考试与写代码时的对照物。#include stdio.h // 预处理指令包含标准输入输出头文件C89 起即为标准写法 int main(void) // 主函数程序入口返回整数类型void 表示不接受参数 { printf(文字\n); // 标准库函数格式化输出内容到屏幕 return 0; // 向操作系统返回 0表示程序正常结束 }元素全称中文含义说明#includeinclude包含预处理指令把头文件内容搬进来stdio.hstandard input/output header标准输入输出头文件printf 的说明书所在intinteger整数main 的返回类型mainmain主要的程序入口每个程序有且仅有一个voidvoid空、无表示不接受任何参数printfprint formatted格式化打印输出函数\nnewline新行换行转义字符return 0return返回退出码 0 正常结束注C 语言标准只规定 int 类型的最小取值范围-32767 至 32767实际宽度随平台不同32 位系统中常见为 4 字节。这个标准只定下限的设计正是下一章内存与数据组织要展开的话题。练习以下练习均在编程环境中直接运行验证。第 1 题改编自一本通 OJ 1001 题其余为本书配套练习写作组已在应用内题库配置对应题号。输出Hello, World!改编自一本通 1001输出三行文字每行一句I am learning C.、This is line two.、Line three.输出自己的名字与班级格式为两行输出一个空行再输出C is fun.练习空行的输出方式用\t制表符tab 的缩写输出两列对齐的文字Name Score输出一句话He said C is great.练习\转义——引号本身也是特殊字符输出一个反斜杠\练习\\转义用*输出一个直角三角形图案三行第一行一个星号第二行两个第三行三个输出如下字母块ABC DEF GHI综合题输出一张程序名片第一行是课程名C Programming第二行是章节Chapter 1第三行是日期占位文字Date: ____-__-__要求三行之间以一个空行分隔。本章回顾计算机的母语是机器语言0 和 1人类直译不可行。汇编语言用助记符完成第一次反击但仍与机器型号死绑。Fortran 开创高级语言时代高级语言的样貌是类英语的简化。易语言的反例工具受制于物理载体键盘生态锁死于起点。编程语言的进化线机器语言 → 汇编 → 高级语言 → 自然语言人类与机器相向而行C 站在第三阶段的巅峰。第一个程序的现代写法int main(void) 与 return 0是标准演进的产物每个多出来的字都有历史。编译整本翻译源代码 → 编译器 → 可执行程序。下一章程序跑起来了但数据存在哪从内存的角度看数据是如何被组织的以及那道 32768 的超界冤案真正的历史谜底。参考文献本章史料经 AI 查证与人工复核主要来源如下。Hollerith 打孔卡制表机与美国人口普查美国人口普查局U.S. Census BureauHollerith 机器专页1880 年普查统计耗时八年、1890 年换用打孔卡后人口总数于 1890 年 8 月 16 日开工六周宣布。80 列打孔卡标准Smithsonian 国家美国历史博物馆 IBM 80 列卡藏品说明1890 年 Hollerith 卡为 45 列圆孔1928 年 IBM 定 80 列方孔标准「打孔卡到终端宽度」的完整传播链在史学上有讨论80 列源自打孔卡为公认。Grace Hopper 与 A-0 编译器IEEE 里程碑「Grace Hoppers Compiler and Programming Language Work, 1952-1959」美国海军历史档案馆生平页海军少将、USS Hopper DDG-70 以其命名。FortranIBM 1957 年发布John Backus 领队第一个被广泛使用的高级语言「编译代码不可能比手写汇编快」的质疑被优化器实测终结。易语言吴涛 2000 年 9 月 11 日首发易语言官网及公开资料。C99 取消隐式 int 与隐式函数声明ISO/IEC 9899:1999C99 标准FreeBSD c99(7) 手册变更清单。退出码 0 表示成功早期 UNIX 的约定POSIX「Shell Command Language」IEEE Std 1003.1形式化。KR《The C Programming Language》1978 年第一版为 C 的事实标准直至 1989 年 ANSI 标准X3.159-1989。
返回列表