C语言概述
C语言简介
一提到语⾔这个词语,自然会想到的是像英语、汉语等这样的自然语⾔,因为它是人和人交换信息不可缺少的工具。而今天计算机遍布了我们生活的每一个角落,除了人和人的相互交流之外,我们必须和计算机交流。
用什么的什么样的方式和计算机做最直接的交流呢?人们自然想到的是最古老也最方便的方式——语⾔,而C语⾔就是人和计算机交流的一种语⾔。语⾔是用来交流沟通的:有一方说、有另一方听,必须有两方参与,这是语⾔最重要的功能:
- 说的一方传递信息,听的一方接收信息;
- 说的一方下达指令,听的一方遵循命令做事情。
语⾔是人和人交流,C语⾔是人和机器交流。只是 人可以不听另外一个人;但是 计算机是无条件服从。语⾔有独特的语法规则和定义,双方必须遵循这些规则和定义才能实现真正的交流。
C语言的起源
以下内容,仅供了解,可以当一个故事看一看。了解C语言的历史背景,也有助于大家理解学习C语言。
C语言是贝尔实验室的Ken Thompson(肯·汤普逊)、Dennis Ritchie(丹尼斯·里奇)等人开发的UNIX 操作系统的“副产品”,诞生于1970年代初。
Thompson和Ritchie共同创作完成了Unix操作系统,他们都被称为。
如果你非要较真谁才是“C语言之父”,那么普遍而言,Dennis Ritchie被认为是,因为他是C语言的主要设计者。
为了表彰他们在“Unix操作系统的设计和实现,以及与之相关的C语言的开发”上的贡献,Dennis Ritchie 和 Ken Thompson 在1983年共同获得了。
除此之外,Thompson还是“UFT-8编码”和“Go语言”的主要发明设计者。
贝尔实验室是什么机构?
贝尔实验室(Bell Labs),全称贝尔电话实验室,创建于1925年,隶属于AT&T公司(美国电话电报公司,曾经大致相当于中国电信加移动加联通,通信领域的超级巨头)。贝尔实验室在20世纪为计算机科学、电信和物理学领域做出了巨大的贡献。
贝尔实验室是美国历史上最有知名度,最具影响力的研究和开发机构之一。
贝尔实验室的贡献包括但不限于:晶体管、Unix操作系统、C语言、光纤、激光等。
关于贝尔实验室,强烈推荐吴军博士的《浪潮之巅》这本书,该书讲解了世界上巨头科技、互联网公司(诸如IBM、Apple、微软等)的兴衰历史。即便将它当成故事书一样去看,也是十分精彩的,值得一看。
吴军博士所著浪潮之巅,故事精彩,语言诙谐,可称为计算机行业的入门必读书籍。
Unix操作系统有什么深远的影响?
可能有些同学(尤其是没怎么接触过计算机的同学),对Unix操作系统没什么印象,但实际上Unix操作系统是计算机历史上最重要,和影响最深远的操作系统之一。
目前市场中最流行的操作系统,可以分为两大类:
- Windows视窗操作系统,是最广泛使用的桌面级操作系统。尤其是PC和办公环境下,Windows无疑是统治者。
- 类Unix操作系统(Unix-like),指那些在设计、功能等方面上与原始Unix有高度相似性或受其启发的操作系统。
- 最常用的类Unix操作系统是MacOS以及Linux。
- 其中MacOS是桌面端足可以和Windows抗衡的操作系统,而Linux则是服务器市场的霸主。
原始的Unix操作系统由于其昂贵的成本,在日常的消费者市场中并没有获得广泛应用。但其设计理念和架构深深影响了后续的操作系统发展,尤其是在MacOS和Linux等类Unix系统中。
然而在一些需要极高可靠性和稳定性的领域,例如银行、金融服务和电信等,Unix操作系统仍然是首选,当然前提是企业具备足够的经济实力。在这些领域,Unix系统的稳定性和安全性成为了决定性的因素,即便成本较高,许多公司也愿意为此支付额外费用。
C语言诞生
上世纪60年代末,Thompson独自编写出了最初版本的Unix操作系统。Unix系统最初是用汇编语言编写的,用汇编语言编写的程序往往难以调试,也不易于进行扩展和移植。
Thompson意识到需要用一种更加高级的编程语言来完成Unix系统未来的开发,于是他设计了一种小型语言——。B语言是在BCPL语言(20世纪60年代中期产生的一种系统编程语言)的基础上,简化开发而来的。
不久,Ritchie也加入到Unix项目中,并且开始着手用B语言编写程序。1970年,贝尔实验室为Unix项目争取到一台PDP-11计算机(一款在70年代非常成功的小型计算机)。当B语言经过改进并能够在PDP-11计算机上运行后,Thompson用B语言重新编写了部分UNIX代码。
到了1971年,B语言由于效率和功能上的局限性,已经明显不适合PDP-11计算机了,于是Ritchie着手开发B语言的升级版。最初,他将新开发的语言命名为NB语言(意为“New B”),但是后来新语言越来越偏离B语言,于是他将其改名为C语言。
这样C语言就诞生了,C语言的前身是B语言,而C语言的发明者是Dennis Ritchie。
使用C语言重写Unix是一个关键决策,它为Unix的成功和普及打下了坚实的基础,使得Unix成为了一个扩展性强、可移植性强、易于开发维护的操作系统。
C语言的发展
1978年,Dennis Ritchie和Brian Kernighan(布莱恩·克尼汉)共同出版了书籍《C编程语言(The C Programming Language)》。这本书中描述的C语言版本经常被称为,
到了80年代,C语言走出贝尔实验室,被广泛使用。不同的机构间,往往会在原有基础上自己扩展一些C语法,这就是“C方言”。
为了确保C语言的一致性和可靠性,美国国家标准协会(ANSI)于1983年设立了一个委员会来标准化C语言。最终,该组织在1989年推出了ANSI C标准,也称为。
不久之后,到了1990年,国际标准化组织(ISO)采纳了这一标准,并在1990年发布了这个C语言版本,被称为。事实上,C89和C90就是两个相同的C语言标准,只是由不同的组织在不同的时间发布罢了。
在这之后,C语言的官方标准版本的发布,都由ISO机构下的C语言相关工作组WG14完成。
1999年,发布。引入了如内联函数、新的数据类型、变长数组等新特性。
2011年,发布。增加了并发支持、类型通用宏、静态断言等新特性。
2018年,发布。主要是对C11进行小维护和小修正,没有引入新特性。可以认为C18就是C11的小更新版本。
除此之外,C11增加了对现代计算机操作系统的支持,特别是关于线程、并发部分的支持,所以在需要这些特性的C语言程序中,会优先选择C11。
总得来说,到目前为止,C99和C11在商业环境中是最常用的版本。
C语言的标准
C 语言自 1972 年首次发布以来,经历了多次修订和更新,导致了几个主要版本:
K&R C (1978)
- C 语言的第一个标准版本,由布莱恩·科尼根和丹尼斯·里奇编写。
- 引入了基本语法、数据类型、控制结构和输入/输出函数。
ANSI C (1989)
- 由美国国家标准协会 (ANSI) 开发的第一个 C 语言标准。
- 添加了新的关键字(如
const
、volatile
和void
)和库函数(如strtok()
和qsort()
)。
C99 (1999)
- 由国际标准化组织 (ISO) 开发的重大修订。
- 引入了复杂数据类型(如结构和联合)、可变参数和内联函数。
C11 (2011)
- 添加了对线程、匿名结构和联合的支持。
- 引入了快速数学函数和原子类型。
C18 (2018)
- 最新版本的 C 语言标准。
- 增加了对通用内存模型和浮点语义的支持。
比较不同版本的 C 语言:
特性 | K&R C | ANSI C | C99 | C11 | C18 |
---|---|---|---|---|---|
复杂数据类型 | 否 | 否 | |||
可变参数 | 否 | 否 | |||
内联函数 | 否 | 否 | |||
线程支持 | 否 | 否 | 否 | ||
快速数学函数 | 否 | 否 | 否 | ||
原子类型 | 否 | 否 | 否 | 否 |
C 语言版本选择:
选择要使用的 C 语言版本取决于应用程序的需求和目标平台。
- 如果需要广泛的兼容性,则 K&R C 或 ANSI C 是不错的选择。
- 如果需要复杂的数据类型、内联函数或可变参数,则 C99 或更高版本是必需的。
- 对于需要线程或原子类型的并行应用程序,则 C11 或 C18 是最佳选择。
值得注意的是,并非所有编译器都支持最新的 C 语言标准。在为应用程序选择版本时,请务必考虑编译器的支持。
语言特点
例如:
- 操作系统。C语言设计的初衷就是用来编写操作系统,目前所有的主流操作系统内核,所采用的编程语言都是C语言。
- 网络协议栈。一般和内核采用相同的语言实现,也就是C语言。
- Web服务器/HTTP服务器。Apache、Nginx主要由C语言编写。Tomcat(Java编写,仅运行Java应用)
- 关系型数据库。PostgreSQL、SQLite主要由C语言编写。MySQL(C/C++)
- 非关系型数据库。Redis主要由C语言编写。MongoDB(C++)、Elasticsearch(Java)
- ...
所谓"中级"编程语言,是要比较的,参看下图:
这意味着C语言有以下优点:
- C语言通过提供直接内存访问、指针操作和系统调用等功能,允许程序员以接近硬件的方式编写代码。这种能力使得C语言特别适用于嵌入式系统开发以及系统级编程。
- C语言提供了接近硬件的操作能力,这意味着C程序可以更好的利用硬件资源。
- C语言编译器将源代码直接编译成机器代码(或非常接近的汇编语言),而非解释执行或编译为中间代码。
- 比如C语言的手动内存分配控制,这意味着可以精确地管理资源使用,从而提高效率。
- 在平均一般情况下,如果一个C程序的执行速度是100%,那么:
- C++可能由于复杂性的影响,性能会轻微下降,一般是95%左右。
- Java由于JVM等特性的影响,运行效率一般低于C/C++,大概在50%-80%范围内。
- Python是一种脚本语言,需要解释执行,效率很差。可能在5%-30%之间。
- 作为一门接近硬件的编程语言,C语言的抽象层次很低,没有很多高级的抽象特性。这使得C语言简单易学,同时对于想要深入理解计算机原理的人来说,C语言的低抽象性也可以使得学习者可以更好的忽略语言特性,关注具体原理。
- C语言作为一门"中级语言",市面上流行的编程语言基本都可以找到它的影子(C-like语言),所以学习C语言对于学习其他编程语言也有很大的帮助。
C语言的生命力旺盛,从诞生到如今始终都是最流行的开发语言之一。
可以参考:TIOBE世界编程语言排行榜
很多时候,一个优点往往同步带来一些缺点,C语言实际上是一门缺点很明显的编程语言。正如丹尼斯·里奇(Dennis M. Ritchie),C语言的主要发明者,曾经评价C语言说:
C is quirky, flawed, and an enormous success.
这句话直译为:“C语言是古怪的、有缺陷的,但同时取得了一个巨大的成功。”
C语言有以下突出的缺点:
- 这主要是因为:
- C语言的语法相对和灵活,给予了程序员很大的自由度,但出错的概率也大大增加了。
- C语言给程序员很大的自主性和控制权限,但即便是熟练的C程序员也无法保证能够完美的控制程序。比如内存管理,手动的内存管理不仅增加了编程的复杂性,而且非常容易出错,如内存泄漏和使用未初始化的内存导致未定义行为。
- C语言追求效率,所以没有专门的异常机制来指示程序出现的问题。C程序甚至不会去检查数组下标越界的问题。
- ...
- C语言缺少一些必要的高级特性,使得C程序的可维护性很差。一个复杂的C程序,如果在设计之初没有考虑到维护问题,那么将很难对它做出修改或扩展。(这也是C++出现的目的)
- 相比较现代的高级语言,C语言经常可以写出可读性十分差的代码。
- 这一方面是由于C语言作为一门小型语言,它缺乏一些现代高级语言中的特性,并且其标准库相对较小。因此,程序员往往需要自行编写复杂的代码实现,这些代码对于其他人可能难以理解。
- 另一方面,C语言诞生于编程发展的初期,那时的编程哲学倾向于代码的极致简洁性。这种风格有时会导致代码过于晦涩难懂,尤其是当程序员过分追求聪明的技巧时,可能会编写出只有自己能理解的代码。
- 在现代编程中,尤其是团队协作环境下,高度重视代码的可读性和维护性。因此,在我们的课堂上,我们会强调编写清晰易读的C代码,而不是单纯追求代码的简洁。
- C语言的核心语法特性在不同编译器和平台之间是保持一致的,这是因为不同平台的编译器实现都必须遵循C语言的标准(如ISO C标准)。这确保了无论在Windows还是Linux平台上,基本的语法、控制结构和数据类型等基础元素都是相同的。
- 然而,由于C语言提供了接近操作系统层面的编程能力,当涉及到与操作系统直接交互的特定功能,如系统调用或使用特定平台的库函数时,就会出现不同平台间的实现差异。
- 这种差异性一方面影响了C语言的跨平台性,也增加了C语言的学习成本。例如,尽管Windows和Linux平台上的C语言核心编程逻辑相似,但在实现平台特定功能时所需的API调用和编程细节可能大不相同。
- 王道的C方向更侧重于服务器端、嵌入式领域等方向,所以在涉及平台交互的场景中,我们将会学习Linux C,这是我们第二阶段的课程内容。
- 需要注意的是,尽管存在平台间的差异,但这并不意味着Windows和Linux下的C语言是两种截然不同的语言。适应不同的平台环境和编程接口对程序员而言,不算什么特别困难的事情。
知识拓展
计算机结构组成
计算机系统组成
64位和32位系统区别
- 寄存器是CPU内部最基本的存储单元
- CPU对外是通过总线(地址、控制、数据)来和外部设备交互的,总线的宽度是8位,同时CPU的寄存器也是8位,那么这个CPU就叫8位CPU
- 如果总线是32位,寄存器也是32位的,那么这个CPU就是32位CPU
- 有一种CPU内部的寄存器是32位的,但总线是16位,准32位CPU
- 所有的64位CPU兼容32位的指令,32位要兼容16位的指令,所以在64位的CPU上是可以识别32位的指令
- 在64位的CPU构架上运行了64位的软件操作系统,那么这个系统是64位
- 在64位的CPU构架上,运行了32位的软件操作系统,那么这个系统就是32位
- 64位的软件不能运行在32位的CPU之上
寄存器名字
8位 | 16位 | 32位 | 64位 |
---|---|---|---|
A | AX | EAX | RAX |
B | BX | EBX | RBX |
C | CX | ECX | RCX |
D | DX | EDX | RDX |
寄存器、缓存、内存三者关系
按与CPU远近来分,离得最近的是寄存器,然后缓存(CPU缓存),最后内存。
CPU计算时,先预先把要用的数据从硬盘读到内存,然后再把即将要用的数据读到寄存器。于是 CPU <--> 寄存器 <--> 内存,这就是它们之间的信息交换。
那为什么有缓存呢?因为如果经常操作内存中的同一址地的数据,就会影响速度。于是就在寄存器与内存之间设置一个缓存。
因为从缓存提取的速度远高于内存。当然缓存的价格肯定远远高于内存,不然的话,机器里就没有内存的存在。
由此可以看出,从远近来看:CPU <--> 寄存器 <--> 缓存 <--> 内存。