C_Primer_Plus01.Getting Ready
Getting Ready
- 要点
C 的歷史和特性
编程步骤
编译器和链接器
C 标准
关于C
C 起源
1972年,贝尔实验室 Dennis Ritchie 和 Ken Thompson 在设计 Unix 操作系统时开发了 C 语言。C 并非从无到有诞生于 Ritchie 的脑海中,而是源于 Thompson 的 B 语言。C语言诞生的初衷是作为一个工具来方便程序员工作,所以C的首要目标是成为一个有用的语言。
大多数语言力图有用,但它们各有其侧重点。例如 Pascal,它的目的是为了方便讲授编程原理。BASIC,一个类英语的编程语言,便于不熟悉电脑的学生更简单的学习编程。这些侧重点是重要的,但不符合实用主义。C是面向程序员而开发的,到目前为止仍然是首选语言之一。
C 特点
- 设计特性
- 擅长自顶向下的设计,结构化编程,模块化程序设计
- 可靠,易读
- 高效
- 代码紧凑,执行效率高
- C语言具有汇编的微调控制能力(根据处理器的指令集进行代码优化),可以获得最优的速度,最有效的内存使用
- 可移植
- 比Basic,Fortran 等有更好的可移植性,C编译器对大多数计算机架构都是可见的
- 要注意的是,对于特殊硬件设备,比如显示器,或特殊功能,比如win8和OSX上的特有功能,C的代码通常不可移植
- Unix,Linux 系统中通常自带C编译器
- 强大且灵活
- 大多数语言的编译器解释器是用C语言写的,比如 Fortran,Perl,Python,Pascal,Lisp,Logo和Basic
- C程序常用于处理物理学和工程学问题,甚至是电影特效
- 面向程序员
- 可通过C来操作硬件,操作内存中的位
- 丰富的运算符使你能够简洁地表达意图
- 比高级语言更加灵活,但这种灵活性增加了犯错的风险
- 大多数C实现都有一个强大的库,它们实现了很多有用的C函数,能够满足程序员的日常需求
- 缺点
- C的灵活性增加了犯错的机会
- C中的指针使得程序难以调试,难以追踪错误
- C的简洁紧凑和大量的运算符,使得C能够写出难以被人模仿的代码;国际年度混乱代码大赛是C所独有的
C应用范围
C与C++:
- 1990s,许多软件公司开始转向C++
- C++在C语言基础上包装了面向对象编程工具
- 面向对象的哲学是,对语言建模来适应问题,而不是对问题建模来适应语言
- C是C++的子集,任何C的程序都是或近似是一个C++程序,所以学习C相当于学习了一部分C++知识
应用范围
- UNIX 操作系统
- 嵌入式系统
- 机器人工厂
- 计算机游戏
- 计算机语言
- PC应用
- 电影
计算机组成
- CPU
- 执行指令,完成计算机的大部分工作
- RAM (random access memory)
- 程序和文件的工作空间
- 硬盘
- 掉电后能存储文件
- 外设(键盘,鼠标,显示屏,触摸板等)
- 与人交互
CPU
CPU的工作非常简单,从内存中读取指令执行,每次读一条,循环往复(频率为1GHz 的CPU 在1秒的时间里能执行10亿次指令,所以CPU是以巨大的速度从事枯燥的工作)。
CPU 的工作空间是一些寄存器,每个寄存器里有一个数值。其中一个寄存器用来存放下一条指令的内存地址,CPU 根据这个地址读取指令,读取指令后将指令存放在另一个寄存器中,并将原来的寄存器更新为下一条指令的地址。
每个 CPU 都有一个指令集,不同型号的cpu指令集不同。指令集是用来用来解释指令的,这些指令通常都非常具体,大部分指令是将某个数值从一个位置移动到另一个位置之类的工作 - 比如从内存移到寄存器。
有两个问题需要申明:1. 计算机中所有的东西都以数字保存。数值型数据是数字,文档中的字符也是数字,每个字符有一个数值的编码。寄存器中的指令也是数字。2. 计算机程序最终由数字化的指令码表示,即机器语言。
一个加法计算可被分解为多条指令:
- 将内存2000位置的数字复制到寄存器1
- 将内存2004位置的数字复制到寄存器2
- 将寄存器2加到寄存器1上,并将结果保留在寄存器1中
- 将寄存器1的内容复制到内存2008的位置里
高级计算机语言和编译器
在机器语言的时代,你须得精确地知道一个特定的CPU是如何完成一个特定的任务,而在高级语言时代,一行简单的代码就能代替数行费力写出来的机器码。高级语言对人类是友好的,而对计算机简直就是胡言乱语。编译器是两者的桥梁,将高级语言转换成机器语言的指令集合。
编译器使得高级语言具有跨平台性,编码一次,多平台编译执行。
语言标准
目前已有许多C语言的实现(编译器)理想情况下,在不同的实现下运行同样的程序,应当产生相同的结果,就好像这些实现没有对指定的计算机编程。为了做到这一点,不同的实现应当有相同的标准。
C语言最初并没有官方标准。Brain Kernighan 和 Dennis Ritchie (1978) 的 C Programming Language 一书成为了普遍接受的标准,通常称为 K&R C 或 Classic C。这本书附录中的 C Reference Manual 是C实现的指导标准。通常,编译器都会说自己完整地实现了 K&R。虽然这本书的附录里定义了C语言,但它并没有定义C库。因为C语言相比其他语言更依赖于库函数,所以有必要定义一个标准库。然而,由于缺乏官方标准,UNIX实现提供的库已成为了标准库。
第一个 ANSI/ISO C 标准
随着C语言的广泛使用,C社区意识到一个更综合的、更与时俱进的和更严格的标准应当被建立起来。鉴于此,美国国家标准局(ANSI, American National Standards Institute)建立了一个委员会(X3J11, 1983),并最终于1989年公布了一个标准,它定义了C语言标准和标准C库。第二年,国际标准化组织(ISO, International Organization for Standardization)也接受了一个C标准(ISO C)。ANSI/ISO 标准的最终版本被称为 C89(ANSI 标准) 或 C90(ISO 标准)。由于 ANSI 版本比较早,人们常称之为 ANSI C。
委员会有许多指导思想,其中之一是C精神:
- 相信程序员
- 不要妨碍程序员完成需要完成的事情
- 保持语言简单精炼
- 对一个操作只提供一种方法
- 让程序尽可能地快,即使不能保证可移植性
最后一条指的是针对特定电脑定义特定操作以达到最优,而不是强加一些抽象、统一的定义。在学习C语言时常常会遇到这种哲学思想。
C99 标准
1994年,一个叫做 C9X 的委员会 (ANSI/ISO 联合委员会),开始修改上面的标准,产生了 C99 标准。委员会继承了C90标准原有的原则,包括使语言尽可能的小而精。除非是为了满足新需求,委员会不会增加可有可无的新特性。其主要目的之一是支持国际化编程,比如提供国际化字符集。第二个目的是根据既有的编程实践来解决C的缺陷。比如在面对“将C移植到64位处理器”这个问题时,委员会会根据现实中已有的例子和经验来制定标准。第三个目的是提高C的适应性,比如满足科学和工程中对严格数值计算的需求,这使得C比Fortran更有竞争力。
- 国际化
- 修正缺陷
- 数值计算
而在其他方面则比较保守,比如与 C90 和 C++ 的兼容性、保持概念的简洁方面。
关键的一点是C99保留了C的精髓,C仍然是一个简洁高效的语言。本书标出了 C99 的多处修改。虽然新标准已公布有些时日,但并不是所有的编译器都及时更新了C99 标准。你可能会发现有些功能在你的系统里不可用。或者只有在修改了编译器的某些设置后才可用。
C11 标准
2011年 标准委员会 发布了 C11 标准,并提出了一些新的指导原则:
- 在面对程序的安全问题时,”相信程序员”这一条应当被有所限制
- 大部分的C实现只是 C90 标准,并未实现 C99 标准,所以有些 C99 中的特性,在 C11 中变为可选项
- 因为有些实现是针对特定的使用环境,并不需要实现所有功能,为了照顾这些环境,故有此变化
- 为跟进新技术而不是旧标准有缺陷而做出变化
- 比如为了充分利用多处理器,增加了对多线程的支持(可选特性)
使用C编程的7个步骤
- 定义程序的目标
- 输入和输出
- 计算和控制
- 设计程序
- 考虑数据如何表示更容易设计和处理数据
- 编写代码
- 先写思路再编程
- 编译
- 运行程序
- 测试和调试程序
- 维护和修改程序
说明
真正编程时不一定会严格按照上述步骤线性执行,有可能在编写代码的时候发现设计有不合理的地方,会跳回第一步或第二步;另外对程序进行注释会使修改程序变得方便。
示例:
#include <stdio.h>
int main(void){
int dogs;
printf("How many dogs do you have?\n");
scanf("%d", &dogs);
printf("So you have %d dogs!\n", dogs);
return 0;
}
编程机制
目标代码,可执行文件和库
- 编译
- 将源代码转换成中间代码
- 中间代码是机器代码,但不能直接运行
- 链接
- 将中间代码和其他代码合并,生成可执行文件
- 其它代码包括 库代码 和 启动代码
- 库代码
- 程序中使用的第三方库
- 链接时,链接器只会把程序中用到的库函数代码提取出来
- 启动代码
- 与平台(操作系统)有关,不同的平台有不同的启动代码
- 充当程序与操作系统之间的接口
C使用这种分而治之的方法方便对程序进行模块化,可以独立编译单独的模块。通过这种方式,如果只更改某个模块,不必因此重新编译其他模块。

UNIX 系统
UNIX 区分大小写,比如 buget.c 是正确的C文件,而 BUGET.C 不是,因为它使用的是大写C。
在UNIX 上编译
UNIX C编译器名要调用 cc 命令,目前已退出历史舞台.由于历史原因,这个习惯保留了下来,现在UNIX的C编译器以 cc 命令作为编译器的别名。因此,虽然在不同系统中会调用不同的编译器,但用户仍可以继续使用相同的命令:
cc inform.c
编译完后会生成一个 a.out 的文件,直接运行它,就会运行编写的程序。
目标代码是一个后缀为 .o 的文件(对应windows系统的.obj文件),上述的编译中会生成这个文件,但一旦链接器生成了完整的可执行程序,就会将其删除。如果原始程序有多个源文件代码,则保留目标代码文件。

GNU 编译器集合 和 LLVM 项目
GNU, GNU's Not UNIX, 始于1987年,是一个开发大量免费 UNIX 软件的集合。GNU 编译器集合(GCC,其中包含 GCC C 编译器)是该项目的产品之一。GCC 有各种版本以适用于各种硬件平台和操作系统,包括 UNIX, Linux 和 Windows。许多使用 gcc 的系统都用 cc 作为 gcc 的别名。
LLVM(Low Level Virtual Machine, 底层虚拟机) 项目成为 cc 的另一个替代品。是一个与编译器相关的开源软件集合, 始于伊利诺伊大学的2000份研究项目。它的 Clang 编译器处理 C代码,可以通过 clang 调用。有多种版本供不同平台使用,包括 Linux。2012 年,Clang 成为 FreeBSD 的默认 C 编译器。
编译时可以指定标准:
gcc -std=c99 inform.c
gcc -std=c1x inform.c # c1x 是在接受 c11 之前的草案标准
gcc -std=c11 inform.c
Clang 是苹果于2005 年发起的项目,性能优异,报错提示功能友好,支持C/C++, Objective-C/C++,但不如 GCC 支持的平台和语言多。GCC 不仅支持C/C++, 还支持 Java/Fortran/Go 等。当前Clang 的C++标准落后于 GCC。
Linux 系统
linux系统默认安装gcc编译器。
编译命令:
gcc inform.c
PC 的命令行编译器(windows)
C编译器不是标准windows软件包,需要从别处获取并安装C编译器。主要有几种编译器:
- Cygwin
- 在自己的视窗中运行,模仿Linux 命令行环境
- MinGW
- 在Windows 的命令提示模式中运行
- 支持C99,C11最新的一些功能
- Borland 的 C++ 编译器 5.5
- 支持 C90
通常,C编译器生成的中间代码文件后缀为 .obj(或其他,比如.asm的汇编文件)。这些编译器通常不会删除中间文件。
有些编译器编译后会自动运行链接器,另一些则要求用户手动运行链接器。链接后的可执行文件后缀为 .exe。
集成开发环境(Windows)
Microsoft Visual Studio. 目前为止 VS 只选择性地支持那些在C++新特性中能找到的C标准。而且,自2012年版本起,VS不再把C作为项目类型的选项。尽管如此,本书中的绝大多数程序仍可用 VS 来编译。(作为C++程序编译)
初次接触 windows IDE 可能会让人望而生畏,因为它提供了多种目标,即运行程序的多种环境。比如 IDE 提供了32位 windows 程序、64位 windows 程序、动态链接库文件(DLL)等。许多目标都涉及 windows 图形界面。
通常,windows IDE 既可以处理C也可以处理C++,因此要指定待处理的程序是C还是C++。有些产品用项目类型来区分两者。有些用文件扩展名区分。
Windows/Linux
Macintosh 中的 C
Xcode 开发系统
凭借可处理多种编程语言的能力,可用于多平台,可用于开发超大型项目
可使用 clang 或 gcc c编译器 来编译c代码(以前默认gcc,现在是clang)
Xcode 中的Clang版本比gcc版本要新
UNIX 系统内置 Mac OS X,终端工具打开的窗口是让用户在UNIX命令行环境中运行程序。苹果标准软件包不提供命令行编译器

浙公网安备 33010602011771号