第一章 初识C语言

1.1 C语言的起源

C语言是基于B语言,为了开发UNIX系统而设计。

1.2 选择C语言的理由

1.2.1 设计特性

融合了计算机科学和实践的控制特性。C语言的设计理念让用户能轻松地完成自顶向下的规划、结构划编程和模块划设计。因此,用C语言编写的成续 更易懂更可靠

1.2.2 高效性

在设计上充分利用当前计算机的优势,因此C程序相对 更紧凑,而且 运行速度很快。C语言具有通常是汇编语言才具 有的微调控能力 (汇编语言是为特殊的中央处理单元设计的一系列内部指令,使用助记符来表示;不同的CPU系列使用不同的汇编语言),可以根据具体情况微调程序以获得最大运行速度或最有效地使用内存。

1.2.3 可移植性

在一种系统中编写的C程序稍作修改或不修改就能在其他系统运行。如需修改,也只需简单更改主程序头文件中的少许项即可。因为许多计算机体系结构都可以使用C编译器(C编译器是把C代码转换成计算机内部指令的程序)。但要注意,程序中针对特殊硬件设备(如,显示监视器)或操作系统特殊功能编写的部分,通常是不可移植的。

1.2.4 强大而灵活

C语言功能强大而且灵活。许多编译器和解释器都是用C语言编写的。C程序可以用于解决物理学和工程学的问题,甚至可以用于制作电影的动画特效。

1.2.5 面向程序员

C语言是为了满足程序员的需求而设计的,程序员利用C可以访问硬件、操控内存中的位。C语言有丰富的运算符,能让程序员简洁地表达自己的意图。这样的灵活性既是优点也是缺点。 优点 :许多任务用C来处理都非常简洁(如,转换数据的格式); 缺点 可能会犯一些莫名其妙的错误,这些错误不可能在其他语言中出现。 C语言在提供更多自由的同时,也让使用者承担了更大责任

大多数C实现都有一个大型的库,包含众多有用的C函数。这些函数用于处理程序员经常需要解决的问题。

C语言的有点:
1. 强大的控制结构;
2. 快速;
3. 代码紧凑——程序更小;
4. 可移植到其他计算机

1.2.6 缺点

C语言的指针,而涉及指针的编程错误往往难以察觉。有句话说的好:想拥有自由就必须时刻保持警惕。
C语言紧凑简洁,结合了大量的运算符。正因如此,我们也可以编写出让人极其费解的代码。

1.3 C语言的应用范围

C语言成为了小型计算机(UNIX系统)使用的主流语言。从那以后,C语言的应用范围扩展到微型机(个人计算机)和大型机。

C++在C语言的基础上嫁接了面向对象编程工具(面向对象编程是一门哲学,它通过语言建模来适应问题,而不是对问题建模以适应语言)。C++几乎是C的超集,这意味着任何C程序差不多就是一个C++程序。C语言也是嵌入式系统编程的流行语言。C语言还从长期被FORTRAN独占的科学编程领域分得一杯羹。最终,作为开发操作系统的卓越语言,C在Linux开发中扮演着极其重要的角色。

1.4 计算机能做什么

在学习如何用C语言编程之前,最好先了解一下计算机的工作原理。这些知识有助于你理解用C语言编写程序和运行C程序时所发生的事情之间有什么联系。

现代计算机由多种部件构成。 中央处理单元(CPU)承担绝大部分的运算工作。随机存取内存(RAM)是存储程序和文件的工作区;而永久内存存储设备即使在关闭计算机后,也不会丢失之前储存的程序和文件。另外,还有各种外围设备(如,键盘、鼠标、出触摸屏、监视器)提供人与计算机之间的交互。CPU负责处理程序,接下来我们重点讨论它的工作原理。

CPU的工作原理非常简单,至少从一下简短的描述中看是这样。*它从内存中获取并执行一条命令,然后从内存中获取并执行下一条指令,诸如此类(一个吉赫兹的CPU一秒钟能重复这样的操作大约十亿次)。CPU有自己的小工作区——由若干个寄存器组成,每个寄存器都可以储存一个数字。一个寄存器储存下一条指令的内存地址,CPU使用该地址来获取和更新下一条指令。在获取指令后,CPU在另一个寄存器中储存该指令,并更新第一个寄存器存储下一条指令的地址。CPU能理解的指令有限(这些指令的集合叫做指令集)。而且,这些指令相当具体,其中的许多指令都是用于请求计算机把一个数字从一个位置移动到另一个位置。

其一,存储在计算机中的所有内容都是数字。计算机以数字形式储存数字和字符。每个字符都有一个数字码。计算机载入寄存器的指令也以数字形式储存,指令集中的每条指令都有一个数字码。其二,计算机程序最终必须以数字指令码(即,机器语言)来表示。

简而言之,计算机的工作原理:必须提供特殊的指令列表(程序),确切的告诉要做的事情以及如何做。你必须用计算机能直接明白的语言(机器语言)创建程序。例如,计算机要完成两数相加这样简单的事,就得分成类似一下几个步骤:
1.从内存位置2000上把一个数字拷贝到寄存器1;
2.从内存位置2004上把另一个数字拷贝到寄存器2;
3.把寄存器2中的内容与寄存器1中的内容相加,把结果储存在寄存器1中;
4.把寄存器1中的内容拷贝到内存位置2008。
而你要做的是,必须用数字码来表示以上的每个步骤!

1.5 高级计算机语言和编译器

高级语言以多种方式简化了编程工作。首先,不必用数字码表示指令;其次,使用的指令更贴近你如何想这个问题。使用高级编程语言,可以在更抽象的层面表达你的想法,不应考虑CPU在完成任务时具体需要哪些步骤。例如,对于两个数相加,可以这样写:
total = mine + yours;
对我们而言,关看这行代码就知道要计算机做什么;但是,对于计算机而言却恰恰相反。在计算机看来,高级指令就是一堆无法理解的无用数据。编译器 在这里就派上用场了。编译器 就是把高级语言程序翻译成计算机能理解的机器语言指令集的程序。程序员进行高级思维活动,而编译器负责处理冗长乏味的细节工作。
编译器还有一个优势。一般而言,不同CPU制造商使用的指令系统和编码格式不同。但是,可以找到与特定类型CPU匹配的编译器。因此,使用合适的编译器或编译器集,便可把一种高级语言程序转换成供各种不同类型CPU使用的机器语言程序。一旦解决了一个编程问题,便可让编译器集翻译成不同CPU使用的机器语言。
高级语言以更抽象的方式描述行为,不受限于特定CPU或指令集。而且,高级语言简单易学,用高级语言编程比用机器语言编程容易得多。

1.6 语言标准

在理想情况下,编写C程序时,假设该程序中未使用机器特定的编程技术,那么它的运行情况在任何实现中都应该相同。要在实践中做到这一点,不同的实现要遵循同一个标准。

1.7 使用C语言的7个步骤

C是编译型语言。如果之前使用过编译型语言(如,Pascal 或 FORTRAN),就会很熟悉组建C程序的几个基本步骤。但是,如果以前使用的是解释型语言(如,BASIC)或面向图形界面语言(如,Visual Basic),或者甚至没接触过任何编程语言,就有必要学习如何编译。别担心,这并不复杂。首次,为了让读者对编程有大概的了解,我们把编写C程序的过程分解成7个步骤。注意,这是理想状态。在实际的使用过程中,尤其是在较大型的项目中,可能要做一些重复的工作,根据下一个步骤的情况来调整或改进上一个步骤。

1.7.1 第一步:定义程序目标

在动手写程序之前,要在脑中有清晰的思路。想要程序去做什么,首先自己要明确自己想做什么,思考你的程序需要哪些信息,要进行哪些计算和控制,以及程序应该要报告什么信息。这一步中,不涉及具体的计算机语言,应该用一般术语来描述问题。

1.7.2 第二步 设计程序

对程序应该完成什么任务有概念性的认识后,就用该考虑如何用程序来完成它。除此之外,还要完成在程序(还有可能是辅助文件)中如何表示数据,以及用什么方法处理数据。
再次强调,应该用一般术语来描述问题,而不是具体的代码。但是,你的某些决策可能取决于语言的特性。

1.7.3 第三步 编写代码

设计好程序后,就可以编写代码来实现它。在这一步中,应该给自己编写的程序添加文字注释。最简单的方式是使用C的注释工具在源代码中加入对代码的解释。

1.7.4 第四步 编译

接下来的这一步是编译源代码。再次提醒读者注意,编译的细节取决于编程的环境。
前面介绍过,编译器是把源代码转换成可执行代码的程序。可执行代码是用计算机的机器语言表示的代码。这种语言由数字吗表示的指令组成。如前所述,不同的计算机使用不同的机器语言方案。C编译器负责把C代码翻译成特定的机器语言。此外,C编译器还将源代码与C库(库中包含大量的标准函数供用户使用)的代码合并成最终的程序(更精确地说,应该是由一个被称为链接器的程序来链接库函数,但是在大多数系统中,编译器运行链接器)。其结果是,生成一个用户可以运行的可执行文件,其中包含着计算机能理解的代码。
编译器还会检查C语言程序是否有效。如果C编译器发现错误,就不生成可执行文件并报错。理解特定编译器报告的错误或警告信息是程序员要掌握的另一项技能。

1.7.5 第五步 运行程序

传统上,可执行文件是运行的程序。在常见环境(Windows命令提示符模式、UNIX终端模式和Linux终端模式)中运行程序要输入可执行文件的文件名,而其他环境可能要运行命令(在VAX中的OpenVMS)或一些其他机制。例如,在Windows和Macintosh提供的集成开发环境(IDE)中,用户可以在IDE中通过选择菜单中的选项或按下特殊键来编辑和执行C程序。最终生成的程序可通过单击或双击文件名或图标直接在操作系统中运行。

1.7.6 第六步 测试和调试程序

接下来,应该检查程序是否按照你所设计的思路运行。你会发现你的程序中有一些错误,称作bug。查找并修复程序错误的过程叫调试。

1.7.7 维护和修改代码

创建完程序后,你发现程序有错,或者想扩展程序的用途,这时就要修改程序。如果在编写程序时清楚地做了注释并采用了合理的设计方案,这些事情都很简单。

1.7.8 说明

编程并非像描述那样是一个线性的过程。有时,要在不同的步骤之间往复。

要养成先规划再动手编写代码的好习惯,用纸和笔记录下程序的目标和设计框架。这样在编写代码的过程中会更加得心应手、条理清晰。

1.8 编程机制

生成程序的具体过程因计算机环境而异。C是可移植性语言,因此可以在许多环境中使用。用C语言编写程序时,编写的内容被储存在文本文件中,该文件被称为 源代码文件(source code file)。大部分C系统,都要求文件名以 .C 。在文件名中,点号( . )前面的部分称为 基本名(basename),点号后面的部分称为 扩展名

1.8.1 目标代码文件、可执行文件和库

C编程的基本策略是,用程序把源代码文件转换为可执行文件(其中包含可直接运行的机器语言代码)。典型的C实现通过编译和链接两个步骤来完成这一过程。编译器把源代码转换成中间代码,链接器把中间代码和其他代码合并,生成可执行文件。C使用这种分而治之的方法方便对程序进行模块化,可以独立编译其他模块,稍后再用链接器合并已编译的模块。通过这种方式,如果只更改某个模块,不必因此重新编译其他模块。另外,链接器还将你编写的程序和预编译的库代码合并。

中间文件有多种形式。我们在这里描述的是最普遍的一种形式,即把 源代码 转换为 机械语言代码 ,并把结果放在 目标代码文件(或简称目标文件)。虽然目标文件中包含机器语言代码,但是并不能直接运行该文件。因为目标文件中储存的是编译器的源代码,这还不是一个完整的程序。

目标代码文件缺失 *启动代码(startup code)。启动代码充当着程序和操作系统之间的接口。

目标代码还缺少库函数。几乎所有的C程序都要使用C标准库中的函数。

链接器 的作用是,把你编写的目标代码、系统的标准启动代码和库代码这3部分合并成一个文件,即可执行文件。对于库代码,链接器只会把程序中要用到的库函数代码提取出来。

graph TD
        A[源代码] -> B[编译器]
        B --> C[目标代码]
        C --> D[链接器]
        D --> E[可执行代码]
        F[代码库] --> D
        G[启动代码] --> D

简而言之,目标文件和可执行文件都由机器语言指令组成的。然而,目标文件中只包含编译器为你编写的代码翻译的机器语言代码,可执行文件中还包含你编写的程序中使用的库函数和启动代码的机器代码。

有些系统中,必须分别运行编译程序和链接程序而在另一个系统中,编译器会自动启动链接器,用户只需给出编译命令即可。

1.8.2 UNIX系统

由于C语言因UNIX系统而生,也因此而流行,所以我们从UNIX系统开始( 注意:我们提到的UNIX还包含其他系统,如FreeBSD,它是UNIX的一个分支,但是由于法律原因不使用该名称)。

1. 在UNIX系统上编辑

UNIX C 没有自己的编辑器,但是可以使用通用呆UNIX编译器。

作为程序员,要负责输入正确的程序和为储存该程序的文件起一个合适的文件名。

#include <stdio.h>
int main(void){
    printf("A .c is used to end a C program filename.\n");
    return 0;
}

2. 在UNIX系统上编译

计算机不明白 #includeprintf 是什么。如前所述,我们需要编译器将我们编写的代码(源代码)翻译成计算机能看懂的代码(机器代码)。最后生成的可执行文件中包含计算机要完成任务所需的所有机器代码。

用户需要使用编译命令进行编译(以前,UNIX C编译器要调用语言定义的 cc 命令。但是,它没有跟上标准发展的脚步,已经退出了历史舞台)。几秒钟后,会返回UNIX的提示,告诉用户任务以完成。如果编写有误,你可能会看到警告或错误消息。如果使用1s命令列出文件,会发现有一个a.out文件,该文件是包含已编译的可执行文件。

如何处理目标代码?C编译器会创建一个与源代码基本名相同的目标代码文件,但是其扩展名是 .o 。

1.8.3 GNU编译器集合和LLVM项目

GNU是一个开发大量免费UNIX软件的集合(GNU的意思是“GNU’s Not UNIX“)。GNU编译器集合(也被称为GCC,其中包含GCC C编译器)是该项目的产品之一。GCC在一个指导委员会的带领下,持续不断地开发,它的C编译器紧跟C标准的改动。

LLVM项目成为 cc 的另一个替代品。该项目是与编译器相关的开源软件集合。

1.8.4 Linux系统

Linux是一个开源、流行、类似于UNIX的操作系统,可在不同平台(包括PC和Mac)上运行。在Linux中准备C程序与在UNIX系统中几乎一样,不同的是要使用GNU提供的GCC公共域C编译器。

注意,在安装Linux时,可选择是否安装GCC。如果之前没有安装GCC,则必须安装。通常,安装过程会将cc作为gcc的别名,因此可以在命令行中使用cc来代替gcc。

1.8.5 PC的命令行编译器

C编译器不是标准Windows软件包的一部分,因此需要从别处获取并安装C编译器。可以下载免费的Cygwin和MinGW,这样便可在PC上通过命令行使用GCC编译器。

源代码文件应该是文本文件,不是字处理器文件(字处理器文件包含许多额外的信息,如字体和格式等)。因此,要使用文本编译器来编辑源代码。如果使用字处理器,要更改文件名后缀,把 txt 替换成 c

1.8.6 集成开发环境(Windows)

许多供应商都提供Windows下的集成开发环境,或称为IDE。

1.8.7 Windows/Linux

许多Linux发行版都可以安装在Windows系统中,以创建双系统。一些储存器会为Linux系统预留空间,以便可以启动Windows或Linux。可以在Windows系统中运行Linux程序,或在Linux系统中运行Windows程序。不能通过Windows系统访问Linux文件,但是可以通过Linux系统访问Windows文档。

1.8.8 Macintosh中的C

苹果免费提供Xcode开发系统下载。它允许用户选择不同的编程语言。

UNIX系统内置Mac OS X,终端工具打开的窗口是让用户在UNIX命令行环境中运行程序。苹果在标准软件包中不提供命令行编译器,但是,如果下载了Xcode,还可以下载可选的命令行工具,这样就可以使用clang和gcc命令在命令行模式中编译。

1.9 本章小节

C是强大而简洁的编程语言。它之所以流行,在于自身提供大量的使用编程工具,能很好地控制硬件。而且,与大多数其他程序相比,C程序更容易从一个系统移植到另一个系统。

C是编译型语言。C编译器和链接器是把C语言源代码转换成可执行代码的程序。

用C语言编程可能费力、困难,让你感到沮丧,但是它也可以激发你的兴趣,让你兴奋、满意。我们希望你在愉快的学习过程中爱上C。

1.10 复习题

1. 对编程而言,可移植性 意味着什么?

完美的可移植程序是,其源代码无需修改就能在不同计算机系统中成功编译的程序。

2. 解释源代码文件、目标代码文件和可执行文件有什么区别?

源代码文件:包含程序员使用的任何编程语言编写的代码。目标代码文件包含机器语言代码,它不必是完整的程序代码。

可执行代码文件:包含组成可执行程序的完整机器语言代码。

3. 编程的7个主要步骤是什么?

(1)定义程序目标;
(2)设计程序;
(3)编写程序;
(4)编译程序;
(5)运行程序;
(6)测试和调试程序;
(7)维护和修改程序。

4. 编译器的任务是什么?

把源代码翻译成等价的机器语言代码。

5. 链接器的任务是什么?

把翻译器翻译好的源代码以及库代码和启动代码组合起来,生成一个可执行程序。

1.11 编程练习

1. 你刚被MacroMuscle有限公司聘用。该公司准备进入欧洲市场,需要把一个英寸单位转换为厘米单位(1 英寸 = 2.54 厘米)的程序。该程序要提示用户输入英寸值。你的任务是定义程序目标和设计程序(编程过程的第1步和第2步)。

(1)程序目标:英寸单位转换为厘米的工具;
(2)设计程序:
1. 让用户输入英寸值
2. 获取用户输入的英寸值
3. 将用户输入的英寸值 乘以 2,54 储存在一个double变量 d 里
4. 向用户展示转换的厘米值。

猜你喜欢

转载自blog.csdn.net/karashok/article/details/79954309