本章介绍以下内容:
欢迎来到C语言的世界,C是一门功能强大的专业化编程语言,深受业余编程爱好者和专业程序员的喜爱。本章为读者学习这一强大而流行的语言打好基础,并介绍几种开发C程序最可能使用的环境。
我们先来了解C语言的起源和一些特性,包括它的缺点。然后,介绍编程的起源并探讨一些编程的基本原则。最后,讨论如何在一些常见的系统中运行C程序。
1.1 C语言的起源
1972年,贝乐实验室的丹尼斯-里奇(Dennis Ritch)和肯-汤普逊(Ken Thompson)在开发UNIX操作系统时设计了C语言。然而,C语言不完全是里奇突发奇想而来,他是在B语言(汤普逊发明)的基础上进行设计。至于B语言的起源,那是另一个故事。C语言设计的初衷是将其作为程序员使用的一种编程工具,因此,其主要目标是成为有用的语言。
虽然绝大多数语言都以实用为目标,但是通常也会考虑其他方面。例如,Pascal的主要目标是为更好地学习编程原理提供扎实的基础;而BASIC的主要目标是开发出类似英文的语言,让不熟悉计算机的学生轻松学习编程。这些目标固然很重要,但是随着计算机的迅猛发展,它们已经不是主流语言。然而,最初为程序设计开发的C语言,现在已成为首先的编程语言之一。
1.2 选择C语言的理由
在过去40多年里,C语言已成为最重要、最流行的编程语言之一。它的成长归功于使用过的人都对它很满意。过去的20多年里,虽然许多人都从C语言转而使用其他编程语言(如,C++、Objective C、Java等),但是C语言仍凭借自身实力在众多语言中脱颖而出。在学习C语言的过程中,会发现它的许多优点(见图1.1)。下面,我们来看看其中较为突出的几点。
1.2.1
C是一门流行的语言,融合了计算机科学理论和实践的控制特性。C语言的设计理念让用户能轻松地完成自顶向下的规划、结构化编程和模块化设计。因此,用C语言编写的程序更易懂、更可靠。
1.2.2 高效性
C是高效的语言, 设计上,它充分利用了当前计算机的优势,因此C程序相对更紧凑,而且运行速度很快。实际上,C语言具有通常是汇编语言才具有的微调控制能力(汇编语言是为特殊的中央处理单元设计的一系列内部指令,便用助词符表示:不同的CPU系列使用不同的汇编语言),可以根据具体情况微调程序以获得最大运行速度或最有效地使用内存。
1.2.3 可移植性
C是可移植的语言,这意味着,在一种系统中编写的C程序稍作修改或不修改就能在其他系统运行。如需要修改,也只需要简单更改主程序头文件的少许项即可。大部分语言都希望成为可移植语言,但是,如果经历过把IBM PB BASIC程序转成苹果BASIC(两者是近亲),或者在UNIX系统中运行IBM大型机的FORTRAN程序的人都知道,移植是最麻烦的事。C语言是可移植方面的佼佼者。从8位处理器到克雷超级计算机,许多计算机体系结构都可以使用C编译器(C编译器是把C代码转换成计算机内部指令的程序)。但是要注意,程序中针对特殊硬件设备(如,显示监视器)或操作系统特殊功能(如,Windows8 或OS X)编写的部分,通常中不可移植的。
由于C语言与UNIX关系密切,UNIX系统通常会将C编译器作为软件包的一部分。安装Linux时,通常也会安装C编译器。供个人计算机使用的C编译器很多,运行各种版本的Windows和Macintosh(即Mac)的PC都能找到合适的C编译器。因此,无论是使用家族计算机、专业工作站。还是大型机,都能找到针对特定系统的C编译器。
1.2.4 强大而灵活
C语言功能强大且灵活(计算机领域经常使用这两个词)。例如,功能强大且灵活的UNIX操作系统,大部分是用C语言写的;其他语言(如,FORTRAN、Perl、Python、Pascal、LISP、Logo、BASIC)的许多编译器和解释器都是用C语言编写的。因此,在UNIX机上使用FORTRAN时,最终是由C程序生成最后的可执行程序。C程序可以用于解决物理学和工程学的问题,甚至可用于制作电影的动画特效。
1.2.5 面向程序员
C语言是为了满足程序员的需求而设计的,程序员利用C可以访问硬件、操作内存中的位。C语言有丰富的运算符,能让程序员简洁地表达自己的意图,C没有Pascal严谨,但是却比C++的限制多。这样的灵活性性既是优点也是缺点。优点是,许多任务用C来处理都非常简洁(如,转换数据的格式);缺点是,你可能会犯一些莫名其妙的错误, 这些错误不可以在其他语言中出现。C语言在提供更多自由的同时,也让使用者承担了更大的责任。
另外,大多数C实现都有一个大型的库,包含众多有用的C函数,这些函数用于处理程序员经常需要解决的问题。
1.2.6 缺点
人无完人,金无足赤。C语言也有一些缺点。例如,前面提到的,要享受用C语言自由编程乐趣,就必须承担更多的责任。特别是,C语言使用指针,而涉及指针的编程错误往往难以察觉。 有句话说的好:想拥有自由就必须时刻保持警惕。
C语言紧凑简洁,结合了大量的运算符。正因如此,我们也可以编写出让人极其费解的代码。虽然没必要强迫自己编写晦涩的代码,但是有兴趣写写也无妨。试问,除C语言外还为哪种语言举办过年度混乱代码大大赛?
1.3 C语言的应用范围
早在2-世纪80年代,C语言就已经成为小型计算机(UNIX系统)使用的主流语言。从那以后,C语言的应用范围扩展到微型机(个人计算机)和大型机(庞然大物)。如图1.2所示,许多软件公司都用C语言来开发文字处理程序、电子表格、编译器和其他产品,因为用C语言编写的程序紧凑而高效。更重要的是,C程序很方便修改,而且移植到新型号的计算机中也没什么问题。
无论是软件公司、经验丰富的C程序员,还是其他用户,都能从C语言中收益。越来越多的计算机用户转而求助C语言解决一些安全问题。不一定非得是计算机专家也能使用C语言。
20世纪90年代,许多软件公司开始改用C++来开发大型的编程项目。C++在C语言的基础上嫁接了面向对象编程工具(面向对象 编程是一门哲学,它通过对语言建模来适应问题,而不是对问题建模以适应语言)。C++几乎是C的超集,这意味着任何C程序差不多就是一个C++程序。学习C语言,也相当于学习了许多C++的知识。
虽然这些年来C++和JAVA非常流行,但是C语言仍是软件业中的核心技能。在最想具备的技能中,C语言通常位居前十。特别是,C语言已成为嵌入式系统编程的流行语言。也就是说,越来越多的汽车、照相机、DVD播放机和其他现代化设备的微处理器都用C语言进行编程。除此之外,C语言还从长期被FORTRAN独占的科学编程领域分得一杯羹 。最终,作为开发操作系统的卓越语言,C在Linux开发中扮演着极其重要的角色。因此,在进入21世纪的第2个10年中,C语言仍然保持着强劲的势头。
简而言之,C语言是最重要的编程语言之一,将来也是如此。如果你想拿下一份编程的工作,被瓿到是否会C语言是,最好回答是“是”。 1.4 计算机能做什么
在学习如何用C语言编程之前,最好了解一下计算机的工作原理。这些知识有助于你理解用C语言编写程序和运行C程序时所发生的事情之间有什么联系。
现代的计算机由多种部件构成。中央处理单元(CPU)承担绝大部分的运算工作。随机存取内存(RAM)是存储程序和文件的工作区;而永久内存存储设备(过去一般批机械硬盘,现在还包括固态硬盘)即使在关闭计算机后,也不会丢失之前储存的程序和文件。另外,琮有各种外因设备(如,键盘、鼠标、触摸屏、监视器)提供人与计算机间的交互。CPU负责处理程序,接下来我们重点讨论综的工作原理。
CPU的工作非常简单,至少从以下简短的描述中看是这样。它从内存中获取并执行一条指令,然后再从内存中获取并执行下条指令,诸如此类(1GHZ的CPU一秒钟能重复这样的操作大约十亿次,因此,CPU能以惊人的速度从事枯燥的工作)。CPU有自己的小工作区-------由若干个寄存器组成,第个寄存器都可以储存一个数字。一个寄存器存下一条指令的内存地址,CPU使用该地址来获取更新下一条指令。在获取指令后,CPU在另一个寄存器中储存该指令,并更新第1个寄存器存下一条指令的地址,CPU能理解的指令有限(这些指令的集合叫作指令集)。而且,这些指令相当具体,其中的许多指令都是用于请求计算机把一个数字从一个位置移动到另一个位置。例如,从内存移到到寄存器。
下面介绍两个有趣的知识。其一,储存在计算机中的所有内容都是数字。其二,计算机程序最终必须以数字指令码(即,机器语言)来表示。 1.5 高级计算机语言和编译器
高级编程语言(如,C)以多种方式简化了编程工作。首先,不必用数字码表示指令;其次,使用的指令更贴近你如何想这个问题,而不是类似计算机那样繁琐的步骤。
编译器是把高级语言程序翻译成计算机能理解的机器语言指令集的短叶马唐 。程序员进行高级思维活动,而编译顺则负责处理冗长乏味的细节工作。
编译器还有一个优势,一般而言,不同CPU制造商使用的指令系统和编码格式不同。
1.6 语言标准
1987 K&R C "C语言参考手册"已成为实现C语言的指导标准。
1.6.1 第1个ANSI/ISO C标准
C89或C90 ANSI C
1.6.2 C99标准
虽然该 标准已发布了很长时间,
1.6.3 C11标准
1.7 使用C语言的7个步骤
1.7.1 第1步:定义程序的目标
在动手写程序之前,要在脑中有清晰的思路。想要程序去做什么首先自己要明确自己想做什么,思考你的程序要哪些信息,要进行哪些计算和控制,以及程序应该要报告什么信息。在这一步骤中,不涉及具体的计算机语言,应该用一般术语来描述问题。
1.7.1 第2步:设计程序
对程序该完成佬任务有概念性的认识后,就应该考虑如何用程序来完成它。例如,用户界面应该是怎样的?如何组织程序?目标用户是谁?准备花多长时间来完成这个程序?
除此之外,还要决定在程序(还可能是辅助文件)中如何表示数据,以及用什么方法处理数据,学习C语言之初,遇到的问题都很简单,没什么可选的。但是,随着要处理的情况越来越复杂,需要决策和考虑的方面也越来越多。通常,选择一个合适的方式表示信息要可以容易地设计程序和处理数据。
再次强调,应该用一般术语描述问题,而不是用具体的代码。但是,你的某些决策可能取决于语言的特性。例如,在数据表示方面,C的程序员就比Pascal的程序员有更多选择。
1.7.8 说明
编程并非像描述那样是一具线性的过程。有时,要在不同的步骤之间往复。例如,在写代码时发现之前设计不切实际,或者想到了一个更好的解决方案,或者等程序运行后,想改变原来的设计思路,对程序做文字注释为今后的修改提供了方便。
许多初学者经常忽略第1步和第2步(定义程序目标和设计程序),直接跳到第3步(编写代码)。刚开始学习时,编写的程序非常简单,完全可以在脑中构思好整个过程。即使写钷了,也很容易发现。但是,随着编写的程序越来越庞大、越来越复杂,动脑不动手可不行,而且程序中隐藏的错误也越来越难找。最终,那些跳过前两个步骤的人往往浪费了更多的时间,因为他们写出的程序难看、缺乏条理、让人难以理解。。要编写的程序越大越复杂,事先定义和设计程序环节的工作量就越大。
磨刀不误砍柴工,应该养成先规划再动手编写代码的好习惯,用纸和笔记录下程序的目标和设计框架。这样在编写代码的过程中会更加得心应手、条理清晰。
1.8 编程机制
程序清单1.2 c程序
#include
int main(void)
{
printf("Concrete contains gravel and cement.\n");
return 0;
}
1.8.1 目标代码文件、可执行文件和库
C编程的基本策略是,用程序把源代码文件转换为可执行文件(其中包含可直接运行的机器语言代码)。典型的C实现通过编译和链接两个步骤来完成这一过程。编译器把源代码转换成中间代码,链接器把中间代码和其他代码合并,生成可执行文件。C使用这种分而治之的方法方便对程序进行模块化,可以独立编译单独的模块,稍后再用链接器合并已编译的模块。通过这种方式,如果只更改某个模块,不必因此重新编译其他模块。另外,链接器还将你编写的程序和预编译的库代码合并。
中间文件有多种形式。我们在这里描述的是最普遍的一种形式,即把源代码转换为机器语言代码,并把结果放在目标代码文件(或简称目标文件)中(这里假设源代码只有一个文件)。虽然目标文件中包含机器语言代码,但是并不能直接运行该文件。因为目标文件中储存的是编译器翻译的源代码,这还不是一个完整的程序。
目标代码文件缺失启动代码(startup code)。启动代码充当着程序和操作系统之间蝗接口。例如,可以在MS Windows或Linux系统运行IBM PC兼容机。这两种情况所使用的硬件相同,所以目标代码相同,但是Windows和Linux所需要的启动代码不同,因为这些系统处理程序的方式不同。
目标代码还缺少库函数。几乎所有的C程序都要使用C标准库的函数。例如,concrete.c中就使用了printf()函数。目标代码文件并不包含该函数的代码,它只包含了使用printf()函数的指令。printf()函数真正的代码储存在另一个被称为库的文件中。库文件中有许多函数的目标代码。
链接器的作用是,把你编写的目标代码、系统的标准启动代码和库代码这3部分合并成一个文件,即执行文件。对于库存代码,链接器只会把程序中要用到的库函数代码提取出来(见图1.4)。
简而言之,目标谁的和可执行文件都由机器语言指令组成的。然而,目标文件中只包含编译器为你编写的代码翻译的机器语言代码,可执行文件中还包含你编写的程序中使用的库函数和启动代码机器代码。
1.8.2 UNIX系统
1.8.3 GNU编译器集合和LLVM项目
gcc和clang
cc -v
显示你所使用的编译器及其版本。
gcc和clang命令都可以根据不同的版本选择运行时选项来调用不同C标准。
gcc -std=c99 inform.c
gcc -std=c1x inform.c
gcc -std=c11 inform.c
第1行调用C99标准,第2行调用GCC接受C11之前的草案标准,第3行调用GCC 接受的C11标准。Clang编译器在这一点上用法与GCC相同。
1.8.4 LInux系统
要使用GNU提供的gcc 公共域C编译器。编译命令类似于:
gcc inform.c
cc为gcc的别名。
1.8.2 PC的命令行编译器
Cygwin,MinGW,Borland。
1.8.6集成开发环境(Windows)
Microsoft Visual Studio Express
1.8.7 Windows/Linux
1.8.8 Macintosh中的C
Xcode
1.9 本书的组织结构
1.10 本书的约定
2本书使用的系统
"我们的系统"批Imac上运行OS X 10.8.4,Xcode 4.6.2 Clang3.2编译器。
Microsoft Visual Studio Express 2012 ,Pelles C 7.0 Ubuntu 13.04 Linux GCC 4.7.3。