C语言的现代化:语法篇

我坦白,其实我已经很久没用纯C写东西了。但,这不妨碍我赞美一下 C 语言,甚至为它讴歌。

引言

所有的C程序都做同一件事,观察一个字符,然后啥也不干。
——Peter Weinberger

很多人觉得C语言就如同古董一般,丑陋的语法,简陋的标准库,时不时还要考虑一下底层的运行机制,处理指针,动不动就内存泄漏。因此,除非别无选择(如:电子工程师),人们通常不会再去使用这门古老的预言。人生苦短,何苦用C语言呢?

C 语言会被如此诟病,无外乎是因为它太过于底层,在计算机初生的岁月里,还未曾像今天这般精致。那么,掌握C语言有没有必要,大学的第一门编程课是否需要更换成如今如火如荼的Python?我的答案是否定的。

C 语言相对于今天其它高级编程语言来说是比较底层的,这是它的全部优点和缺点的来源。**正因为它足够的底层,所以高手可以驾驭它获得最高的性能,充分地利用计算资源。**计算资源永远是不够的,资本家永远希望能充分利用计算资源来节约成本,C 语言能雄踞 TIOBE 榜这么多年的原因无外如此。另外,在物联网时代,C 语言凭借它的高度可控,优化得当,可以低能耗地作为可穿戴设备的软件开发语言。

幸运的是,C99之后,C语言并没有那么不堪,C语言的衍生工具体系,也已经极大便利了我们。所以,我希望我写的,是21世纪的C语言,摒弃丑陋,留下纯粹的美。

C语言小史

C诡异离奇,缺陷重重,却获得了巨大的成功。
——Dennis Ritchie

世界上出现的第一种高级语言是Algol,它可以算是C语言的前身。Algol的语法和普通语言表达式非常接近,适用于数值计算,多用于科学计算机。1960年,Algol 60推出了很多新概念,如局部性概念、动态、递归、巴科斯-诺尔范式(Backus-Naur Form,BNF)等等。从某种意义上,Algol 60是程序设计语言史上的一个里程碑,它标志着程序设计语言已成为一门独立的学科,并为后来的软件自动化及软件可靠性的发展奠定了基础。

Algol描述算法很方便,但是离计算机硬件系统却很远,不适合用来编写系统程序。1963年英国剑桥大学再Algol语言的基础上添加了处理硬件的CPL(Combined Programming Language,复合程序语言)。CPL规模大、学习难度也大,最终没能流行。1967年,剑桥大学的Martin Richards简化了CPL,推出了BCPL(Basic Combined Programming Language,基本复合程序设计语言)。BCPL是最早使用库函数封装基本输入输出的语言之一,所以它的跨平台移植性很好。

C语言的史前阶段

1969年,通用电气、麻省理工学院和贝尔实验室联合创立了一个庞大的项目——Multics 工程。该项目的目的是创建一个操作系统,但最终不但无法交付原先承诺的快速而便捷的在线系统,甚至连一点有用的东西都没有弄出来。Multics 试图建立一个非常巨大的操作系统,能够应用于规模很小的硬件系统。Multics成了总结工程教训的宝库,但它同时也为 C 语言体现 “小即是美” 铺平了道路。

贝尔实验室的专家们心灰意冷地撤离了 Multics 工程,又开始寻找其他任务。一名叫 Ken Thompson (Go 语言联合创始人之一)的研究人员对另一个操作系统很感兴趣,他为此好几次向贝尔实验室管理层提议,但均遭到否决。在这过程中,Thompson 和他的同事 Dennis Ritchie 自娱自乐,把 Thompson 的“太空旅行”软件移植到不太常用的 PDP-7 系统。后来 Thompson 为PDP-7 系统编写了一个简易的新型操作系统。它比 Multics 简单、轻便。整个系统都是用汇编语言写的。Brian Kernighan 在 1970 年为他取名为 UNIX

确切地说,UNIX系统比C语言出现得早。用汇编语言编写UNIX显得很笨拙,编制数据结构的过程中浪费了大量的时间。于是,Thompson 简化了BCPL,创建了 B 语言。因为硬件系统的内存限制,只能放置解释器,而不是编译器,由此产生的低效阻碍了用 B 语言进行 UNIX 系统的编程的想法。

1970 年开发平台转移到了 PDP-11,无类型的语言很快就不合时宜了。Thompson 在 PDP-11 上重新用汇编语言实现了 UNIX。Dennis Ritchie 利用 PDP-11 的强大性能,创立了能够同时解决多种数据类型和效率的 “New B”(牛B!)(很快就改成了“C”)。它采用编译模式而不是解释模式,引入了类型系统,每个变量在使用前必须先声明。

C语言演化

现代C语言语法

本文假定读者已经了解C语言基本语法。

不要使用void main()

时至今日,还看到有课本在用 void main(),但是,请注意,这个用法不符合任何标准。C 语言标准语法是:

int main()

并且,任何编译器都必须支持

int main(void)

int main(int argc, char *argv[])

另外,C标准知道通常最后的 return 0 极少使用,因此其实是可以省略的。C标准要求:“到达结束main函数的}之前返回一个0值”,也就是说,如果我们没有在程序最后一行写return 0,C编译器会默认加上它。

更灵活的声明

C99以前,变量必须在函数开头声明,这是ANSI C89的古典风格。这样做的原因是早期编译器的技术限制。现在,使用变量前依然需要声明用到的所有变量,但是可以在变量第一次使用的时候才声明它们。从软件工程和可读性角度,都是更好的做法。

/* C89 */
#include <stdio.h>

int main() {
   
  char *head;
  int i;
  double ratio, denom;

  denom = 7;
  head = "There is a cycle to things divided by seven.";
  printf("%s\n", head);
  for (i = 1; i <= 6; i++) {
   
    ratio = i / denom;
    printf("%g\n", ratio);
  }
}

从软件工程的角度,尽可能缩减变量作用域是最好的,减少冲突,也更容易 debug;从代码编写的角度,事先要考虑清楚变量,或者总是要回到开头声明都是很烦的。在 C99 之后,完全可以在需要的时候再声明变量。因此上面的代码可以写成这样:

// 现代C
#include <stdio.h>

int main() {
   
  double denom = 7;
  char *head = "There is a cycle to things divided by seven.";
  printf("%s\n", head);
  for (int i = 1; i <= 6; i++) {
   
    double ratio = i / denom;
    printf(
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值