第1章 Linux基础
Linux C编程从入门到精通
Linux是一套免费使用和自由传播的类UNIX操作系统,它已发展成为现今世界上最流行的一种操作系统。Linux不仅仅能在PC机上运行,随着嵌入式系统的发展,它已经被广泛地应用于各种场合。
1.1 Linux的起源、发展和分类
Linux C编程从入门到精通
Linux从1991年问世到现在已经有20多年的历史,它从一个架构简单的系统内核发展到了现在结构完整、功能丰富的多版本操作系统,本小节将介绍其起源发展和分类。
1.1.1 Linux的起源、特点和版本号
1.起源
Linux 操作系统是一种类UNIX 操作系统,它最早是由芬兰人Linus Torvalds设计的。
在Linux诞生之前,为了教学和研究的需要,阿姆斯特丹Vrije大学的计算机科学家Andrew S. Tanwnbaum以UNIX为蓝本开发了Minix作为一个教育工具。1991 年初,Linus 开始在一台386sx 兼容微机上学习Minix 操作系统。通过学习,他逐渐不满足Minix 系统的现有性能,并开始酝酿开发一个新的免费操作系统,这很快就在Minix新闻组得到了响应。
到了1991 年的10 月5 日,Linus 在comp.os.minix 新闻组上发布消息,正式向外宣布Linux 内核系统(Free minix-like kernel sources for 386-AT:0.02版)的诞生。1991年11月,Linux 0.10版本推出;0.11版本随后在1991年12月推出。当Linux非常接近于一种稳定可靠的系统时,Linus决定将0.13版本改称为0.95版本。后来,在1994年3月,终于出现了带有独立宣言意味的Linux 1.0版本。Linux 1.0已经是一个功能完备的操作系统了,其内核写得紧凑高效,可以充分发挥硬件的性能,在4MB内存的80386机器上也表现得非常好。
事实上,Linux系统是全世界各地成千上万志愿者设计和实现的,其目的是建立不受任何商品化软件版权制约的、全世界都能自由使用的类UNIX操作系统。在Linux操作系统的设计过程中,借鉴了很多UNIX的思想,但源代码是全部重写的。目前Linux操作系统可以运行在x86、Aplpa、MIPS、Power Mac、ARM等类型的计算机上。从功能上来看,它既可以作为普通的桌面操作系统,也可以作为中小型的网络操作系统,甚至还可以作为大型网络的操作系统。
2.特点
Linux具有以下特点。
Linux是一个免费软件。Linux是作为开放源码的免费软件的代表,正是由于这一点,来自全世界的无数程序员参与了Linux的修改和编写工作,程序员可以根据自己的兴趣和灵感对其进行改变。这让Linux吸收了无数程序员的精华,不断壮大。
完全兼容POSIX 1.0标准。POSIX是基于UNIX的第一个操作系统国际标准,这使得可以在Linux下通过相应的模拟器运行常见的DOS、Windows程序。
注意:关于POSIX,将在1.1.5小节中进行介绍。
多用户、多任务系统。Linux支持多用户,各个用户对于自己的文件设备有自己特殊的权利,保证了各用户之间互不影响。多任务则是现在操作系统最主要的特点,Linux中多个程序可以同时独立地运行。
良好的用户界面。Linux向用户提供了两种界面:文本界面和图形用户界面。Linux的传统用户界面是基于文本的命令行界面,即Shell。它既可以联机使用,又可存在文件上脱机使用。
Linux还为用户提供了图形用户界面。可以利用鼠标、菜单、窗口、滚动条等对图形用户界面进行操作。Linux给用户呈现一个直观、易操作、交互性强的友好的图形化界面。Linux的图形用户界面最近几年有很大的改进。在图形用户界面下,几乎可以完成全部的工作。
支持多种文件系统。Linux能支持多种文件系统。目前支持的文件系统有EXT、EXT2、EXT3、XIAFS、ISOFS、HPFS、MSDOS、UMSDOS、 PROC、NFS、XFS、SYSV、MINIX、SMB、UFS、NCP、VFAT、NTFS、AFFS等。
丰富的网络功能。完善的内置网络功能是Linux的一大特点。 Linux在通信和网络功能方面优于其他操作系统。其他操作系统不包含如此紧密地和内核结合在一起的连接网络的能力,而且通信和网络相关功能缺乏灵活性。
可靠的系统安全。Linux采取了许多安全技术措施,包括对读和写进行权限控制、带保护的子系统、审计跟踪、核心授权等,这为网络多用户环境中的用户提供了必要的安全保障。
良好的可移植性。Linux是一种可移植的操作系统,能够在从微型计算机到大型计算机的任何环境中和任何平台上运行。可移植性为运行Linux的不同计算机平台与其他任何机器进行准确而有效的通信提供了手段,不需要另外增加特殊的和昂贵的通信接口。
3.版本号
任何一个软件都有版本号,例如微软的Windows 7,Office 2007等,Linux也不例外。Linux的版本号又分为两部分:内核(Kernel)与发行套件(Distribution)版本。
Linux的内核是系统的心脏,内核包括了几百万行代码,是运行程序和管理硬件设备的核心程序。没有内核,就不能运行程序,但内核不是操作系统的全部。Linux初学者常会把内核版本与发行套件版本弄混,实际上内核版本指的是在Linus领导下的开发小组开发出的系统内核的版本号。Linux的每个内核版本为类似x.y.zz-www的一组数字。其中,x.y为Linux的主版本号,zz为次版本号,www代表发行号(注意,它与发行版本号无关)。当内核功能有一个飞跃时,主版本号升级,如Kernel 2.2、Kernel 2.4、Kernel 2.6等。内核增加了少量补丁时,常常会升级次版本号,如Kernle 2.6.15、Kernel 2.6.20等。当然还有更复杂的版本号系统,如2.6.20-32等。通常,若y为奇数,表示此版本为测试版,系统会有较多漏洞,主要用途是提供给用户测试。随着每一次对系统的小的bug的修正,zz会增加。编写本书时,Linux的内核最新稳定版本号是3.0.3(主版本号3.0表明它是可以使用的稳定版本)。
一般而言,一个基本的Linux只是包含了Linux内核和GNU软件的一些基本的系统软件和实用工具(Utilities),这样一个操作系统仅仅能够让那些Linux专家完成一些很基本的系统管理任务,若要满足普通用户的办公或基于视窗的应用开发等需求,则还需要在系统中加入GNOME、KDE等桌面环境以及相应的办公应用软件(如Office)等。因此一些组织或厂家将Linux系统内核与GNU软件(系统软件和工具)整合起来,并提供一些安装界面和系统设定与管理工具,这样就构成了一个发行套件,例如最常见的Ubuntu,Fedora等。实际上发行套件就是Linux的一个大软件包而已,通常包括C语言及C++的编译器、Perl脚本解释程序、Shell命令解释器、图形用户界面以及众多的应用程序等。相对于内核版本,发行套件的版本号随发布者的不同而不同,与系统内核的版本号是相对独立的。因此把Ubuntu、Fedora等直接说成是Linux是不确切的,它们是Linux的发行版本,更确切地说,应该叫做“以Linux为核心的操作系统软件包”。根据GPL准则,这些发行版本虽然都源自一个内核,并都有自己各自的贡献,但都没有自己的版权。Linux的各个发行版本,都是使用Linus主导开发并发布的同一个Linux内核,因此在内核层不存在兼容性问题。至于每个版本都不一样的感觉,只是在发行版本的最外层才有所体现,而绝不是本身,也不是内核不统一或不兼容。
目前Linux的发行版很多,其中比较流行的国外版本有Ubuntu、Fedora、Slackware、Debian、OpenSUSE和Mandriva等;国内的有红旗Linux和TurboLinux等。
例如最新的Ubuntu的内核版本表示如下(可以通过在终端中输入“uname -a”命令来查看)。
alloeat@Ubuntu:~$ uname -a
Linux Ubuntu 3.2.0-27-generic-pae #43-Ubuntu SMP Fri Jul 6 15:06:05 UTC 2012 i686 i686 i386 GNU/Linux
而其发行套件版本号则表示如下(可以通过“sudo lsb_release -a”命令来查看。需要注意的是,执行这个命令需要超级用户权限)。
Distributor ID: Ubuntu
Description: Ubuntu 12.04 LTS
Release: 12.04
Codename: precise
1.1.2 Linux的结构
Linux既是一个操作系统的名称,也是一个操作系统内核的名称。一个完整的Linux操作系统由Linux内核、Shell、文件系统和实用工具组成,如图1.1所示。
图1.1 Linux的结构
1.Linux内核
内核是Linux操作系统的心脏,是运行程序和管理磁盘、打印机等硬件设备的核心程序。
2.Shell
Shell是系统的用户界面,提供了一种用户与内核进行交互操作的接口。它接收用户输入的命令并把它送入内核去执行。
实际上Shell应该是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。不仅如此,Shell有自己的编程语言,用于对命令进行编辑,它允许用户编写由Shell命令组成的程序。Shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果。
除了Shell之外,Linux同样提供了像Windows那样的可视的命令输入界面,即X Window的图形用户界面(GUI)。它提供了很多窗口管理器,其操作就像Windows操作一样,有窗口、图标和菜单,所有的管理都是通过鼠标控制。现在比较流行的窗口管理器是KDE和GNOME。
注意:X Window的实质是Linux实用工具的一种,请参考“Linux的实用工具”小节。
每个Linux系统的用户可以拥有自己的用户界面或Shell,用以满足他们自己特有的需求。
同Linux本身一样,Shell也有多种不同的版本,下面是目前主流的Shell。
Bourne Shell:是贝尔实验室开发的。
BASH:是GNU的Bourne Again Shell,是GNU操作系统上默认的Shell。
Korn Shell:是对Bourne Shell的发展,大部分内容与Bourne Shell兼容。
C Shell:是SUN公司Shell的BSD版本。
3.Linux的文件结构
文件结构是文件存放在磁盘等存储设备上的组织方法,其主要体现在对文件和目录的组织上。
目录为文件管理提供了一个方便而有效的途径,用户可以从一个目录切换到另一个目录,而且可以设置目录和文件的权限,设置文件的共享程度。在Linux系统中,用户可以设置目录和文件的权限,以便允许或拒绝其他人对其进行访问。Linux目录采用多级树形结构,用户可以浏览整个系统,可以进入任何一个已授权进入的目录,访问其中的文件。
文件结构的相互关联性使共享数据变得容易,几个用户可以访问同一个文件。Linux是一个多用户系统,系统本身的驻留程序存放在以根目录开始的专用目录中,有时被指定为系统目录。
4.Linux的实用工具
Linux操作系统通常都提供一系列叫做实用工具的应用程序,这些实用工具包括与用户进行人机交互的X Window、计算器、浏览器等,主要是用于增加系统可用性。和Windows把这些工具(主要是X Windows)集合到一起不能分离不同,Linux的实用工具都可以让用户自定义。整体来说,Linux的实用工具可分为如下三类。
编辑器。用于编辑文件,Linux常见的编辑器有Ed、Ex、Vi和Emacs。Ed和Ex是行编辑器,Vi和Emacs是全屏幕编辑器。
过滤器。用于接收数据并过滤数据,Linux的过滤器读取从用户文件或其他地方的输入,检查和处理数据,然后输出结果。从这个意义上说,它们过滤了经过它们的数据。Linux有不同类型的过滤器,一些过滤器用行编辑命令输出一个被编辑的文件。另外一些过滤器是按模式寻找文件并以这种模式输出部分数据。还有一些执行字处理操作,检测一个文件中的格式,输出一个格式化的文件。过滤器的输入可以是一个文件,也可以是用户从键盘键入的数据,还可以是另一个过滤器的输出。过滤器可以相互连接,因此一个过滤器的输出可能是另一个过滤器的输入。在有些情况下,用户可以编写自己的过滤器程序。
交互程序。交互程序允许用户发送信息或接收来自其他用户的信息,交互程序是用户与机器的信息接口。Linux是一个多用户系统,它必须和所有用户保持联系。信息可以由系统上的不同用户发送或接收。信息的发送有两种方式,一种方式是与其他用户一对一地链接进行对话,另一种是一个用户对多个用户同时链接进行通信,即所谓广播式通信。
1.1.3 Linux操作系统的分类
前面介绍过,Linux的关键是Linux内核,可以将相同内核通过不同的“包装”生成不同的Linux操作系统,这种包装好的Linux操作系统通常被称为发行版。发行版为许多不同的目的而制作, 包括对不同计算机结构的支持。对一个具体区域或语言的本地化实时应用和嵌入式系统,甚至许多版本故意只加入免费软件。目前,正在开发的Linux发行版超过300个,最普遍使用的发行版有大约12个。
现在市场上存在的Linux发行版种类非常多,但是通常来说可以根据包管理系统或者X Window系统来进行分类。
1.根据包管理系统分类
Linux操作系统中所安装的软件通常都是以包的形式存在的。通常来说,包中除了可执行文件之外,其中还包括了该包的依赖关系、设置文件等。
所谓依赖关系,就是指Linux软件运行所必须的其他条件,比如说软件A在运行的时候需要相应的库a,如果此时没有安装库,则软件A就不能正常运行,通常将这种情况称为软件A的依赖关系没有满足。
由于Linux中软件和库都非常多,并且一个库可能涉及多个软件,所以Linux提供了相应的包管理系统来对这些包进行管理,目前市场占有率最高的两个包管理软件是RPM包管理软件和Deb包管理软件。
RPM包管理软件的全称是Red Hat Package Manager,它是Red Hat公司设计的一套包管理软件,其中包括了软件的可执行程序、相关的配置文件等。用解压缩工具解开RPM包即可以看到其中的内容,但是如果安装RPM包则需要使用相应的包管理工具。
RPM的包管理工具可以提供包的安装、卸载、查询、打包等功能,在打好的包里面有可执行程序以及相应的安装、依赖关系,以下是几个常用的RPM包操作命令。
rpm -vih file.rpm:安装一个RPM包。
rpm -e file.rpm:卸载一个RPM包。
rpm -qpR file.rpm:查看RPM包的依赖关系。
rpm -q file:查询系统已安装的RPM包。
下面是使用RPM包管理工具的常见发行版。
Red Hat。是美国RedHat公司的产品,是相当成功的一个Linux发行版本,也是目前使用最多的Linux发行版本。Red Hat最早由Bob Young和Marc Ewing在1995年创建。原来的Red Hat版本早已停止技术支持,目前Red Hat的Linux分为两个系列,其中一个是由Red Hat公司提供收费技术支持和更新的Red Hat Enterprise Linux系列;另一个是由社区开发的免费的Fedora Core系列。Red Hat因其易于安装而闻名,在很大程度上减轻了用户安装程序的负担,其中RedHat提供的图形界面安装方式与Windows系统的软件安装方式非常类似,这对于那些Windows用户而言,几乎可以像安装Windows系统一样轻松安装Red Hat发行套件。
红旗Linux。是由北京中科红旗软件技术有限公司开发的一系列Linux发行版,包括桌面版、工作站版、数据中心服务器版、HA集群版和红旗嵌入式Linux等产品。
和RPM包管理系统相对应的是Deb包管理系统,Deb的包也是由源代码包和二进制包组成的,其详细说明如下。
源代码包。包括一个描述源代码包的 .dsc 文件,一个包含 gzip-tar 归档压缩格式的未经修改源码的 .orig.tar.gz 文件, 一个包含对源代码作Debian特有修改的 .diff.gz 文件。可以使用 dpkg-source 打包和解压 debian 源码文档。详见联机手册。
二进制包。以.deb扩展名来表示,这些文件通常称为DEB文件,其中包含可执行文件、文档、配置文件和版权信息及其他一些东西。可以使用Debian的dpkg工具解包(安装)。但除去版权信息(和 changelog.Debian 文件)外,二进制包也可以是空的,这种软件包作为过渡包或关联包(也称虚拟包),它们唯一的作用是用于满足依赖性。
一般而言,用户只和二进制包打交道,只有在某些特殊情况下才会求助于源代码包,Debian软件包命名遵循下列约定。
<foo>_<版本号>-<Debian修订号>.deb
Deb包管理系统同样提供了相应的命令,用于管理操作。常用的命令说明如下。
apt命令:用于从源列表(可以是CD、网络等)下载Deb包。
dpkg命令:通过数据库来对系统中的软件进行管理,这个数据库位于/var/lib/dpkg目录中。
aptitude命令:提供图形界面对软件包进行管理,功能较为强大,甚至可以通过终端远程登录运行,如图1.2所示。
图1.2 aptitude命令的运行界面
synaptic:新立得软件包管理器,这是一个运行在X Window环境中的包管理软件,用户可以进行图形化的操作。
gdebi和gdebi-gtk:gdebi是一个命令行的包管理软件,gdebi-gtk是其对应的图形化版本。
dselect:在终端运行的一个图形化软件包管理工具,其功能实现类似synaptic,但是能在终端中运行,如图1.3所示。
采用Deb包管理系统的发行版最常见的是Debian和Ubuntu。
Debian是一款能安装在计算机上使用的操作系统。操作系统就是能让计算机工作 的一系列基本程序和实用工具。由于 Debian 采用了 Linux Kernel (Linux操作系统的核心),但是大部分基础的操作系统工具都来自于GNU工程, 因此又称为 GNU/Linux。Debian GNU/Linux 附带了超过 29 000个软件包,这些预先编译好的软件被包装成一种良好的格式,以便于在机器上进行安装。让Debian 支持其他内核的工作也正在进行,最主要的就是 Hurd。Hurd 是一组在微内核(例如 Mach)上运行的提供各种不同功能的守护进程。
图1.3 dselect的运行界面
Ubuntu是一个以桌面应用为主的Linux操作系统,其名称来自非洲南部祖鲁语或豪萨语的“Ubuntu”一词(译为吾帮托或乌班图),意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu基于Debian发行版和GNOME桌面环境。它与Debian的不同在于它每6个月会发布一个新版本。Ubuntu的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由免费软件构建而成的操作系统。Ubuntu具有庞大的社区力量,用户可以方便地从社区获得帮助。
注意:实际上还存在其他的包管理系统,在此不再过多叙述,有兴趣的读者可以自行去查阅相应的书籍。
2.根据X Window系统进行分类
X Window即X Windows图形用户接口,是一种计算机软件系统和网络协议,它提供了一个基础的图形用户界面(GUI)、丰富的输入设备驱动,并且能提供网络连接,其中软件的编写使用了广义的命令集。它创建了一个硬件抽象层,允许设备独立性和重用方案的任何计算机上实现。
Linux的内核并不像Windows系统那样直接集成了用户能够使用的图形化界面,而X Window即是实现这种功能的应用软件,可以分为KDE和GNOME两大类。
KDE是K桌面环境(Kool Desktop Environment)的缩写,这是一种著名的运行于 Linux、UNIX 以及FreeBSD 等操作系统上的自由图形工作环境,整个系统采用的都是由 TrollTech 公司所开发的 Qt 程序库(现在属于诺基亚公司),具有以下特点。
提供了一个美观的现代化桌面。
提供了一个具有完整的网络透明性的桌面。
提供了一个方便的集成帮助系统,它提供了对KDE桌面及其应用程序帮助的一致化访问途径。
所有的KDE应用程序都具有统一的视觉观感。
具有标准化的菜单、工具栏、键盘绑定、颜色样式等。
国际化支持,KDE已拥有60余种语言的翻译。
集中化组织的对话框系统,由具体的桌面配置来运作。
大量优秀的KDE应用程序。
使用KDE作为X Window系统的常见Linux发行版包括KUbuntu、Fedora、Mint、openSUSE、Mandriva、Debian等。
GNOME是另外一种能在Linux操作系统上运行的X Window应用软件,是GNU计划的一部分。它是一种让使用者容易操作和设置电脑环境的工具,目标是基于免费软件,为UNIX或者类UNIX操作系统构造一个功能完善、操作简单以及界面友好的桌面环境,是GNU计划的正式桌面。GNOME可以运行在包括GNU/Linux(通常叫做Linux)、Solaris、HP-UX、BSD和Apple's Darwin系统上。GNOME 拥有很多强大的特性,如高质量的平滑文本渲染、首个国际化和可用性支持, 并且包括对反向文本的支持(注: 有些国家的文字是从右向左排版的)。
采用GNOME作为默认X Window的Linux发行版并不太多,但是在绝大部分发行版上都可以自行安装,图1.4是一个使用GNOME作为X Window应用界面的Ubuntu的运行界面。
注意:通常来说,X Window只是作为Linux操作系统人机交互的一个应用软件,用户可以根据自己的兴趣爱好等实际情况来自行安装对应的X Window。X Window和其他应用软件在理论上关系不大,但是在实际应用中,由于图形库等依赖关系,一些软件在GNOME上支持得比KDE上好或者差等情况都可能出现,最典型的例子就是在第2章中介绍的VIM和EMACS。
3.本书所选择Linux发行版
本书选择发行版本号为12.04、内核版本号为3.2.0-27、X Window为GNOME 2的Ubuntu系统来介绍Linux下的C语言编程。在实际应用中,由于本书所涉及的大部分知识都只与Linux内核和GCC库相关,所以对于绝大多数发行版而言都是适用的。
图1.4 使用GNOME的Ubuntu操作系统
注意:本书并不涉及Linux的图形编程以及其他的应用软件等深层次的应用。
1.1.4 Linux中的几个术语
在Linux中,有几个术语是Linux下的C语言程序员必须了解的,如GNU、GPL、POSIX和ISO C。
1.GNU
GNU是“GNU's Not UNIX”的缩写,其发音为“Guh-NOO”,原意为非洲牛羚。GNU最开始由Richard Stallman建立于1983年,目的是为了实现一个符合UNIX系统接口标准、软件丰富且可以自由使用的软件库,因此GNU计划可以分别开发不同的操作系统部件。GNU计划采用了部分当时已经可自由使用的软件,例如TeX排版系统和X Window视窗系统等,同时也开发了大批其他的免费软件。
1985年Richard Stallman又创立了免费软件基金会(FSF,Free Software Foundation)其目的是为GNU计划提供技术、法律以及财政支持。尽管GNU计划大部分时候是由个人自愿无偿贡献的,但FSF有时还是会聘请程序员帮助编写。当GNU计划开始逐渐获得成功时,一些商业公司开始介入开发和技术支持,其中最著名的就是之后被Red Hat兼并的Cygnus Solutions。
到1990年,GNU计划已经开发出的软件包括了一个功能强大的编辑器Emacs、GCC(GNU Compiler Collection,GNU编译器集合,也是本书所使用的编译器)以及大部分UNIX系统的程序库和工具,唯一依然没有完成的重要组件就是操作系统的内核。
GNU 包含以下3个协议条款。
GPL:GNU通用公共许可证(GNU General Public License)。
LGPL:GNU较宽松公共许可证 (GNU Lesser General Public License),也被称为 GNU Library General Public License (GNU 库通用公共许可证)。
GFDL :GNU自由文档许可证(GNU Free Documentation License )。
2.GPL
GPL并非由免费软件基金会所发表,亦非使用GNU通用公共授权的软件的法定发布条款,只有GNU通用公共授权英文原文的版本才具有此等效力。
GPL要求在发布软件的同时必须发布源代码,并且允许任何用户能够以源代码的形式将软件复制或者发布给别的用户。如果一个软件使用了遵循GPL的任何软件的全部或者一部分,则该软件也必须遵循GPL。
需要注意的是,GPL并不是免费软件的代名词,其支持商业化的收费软件。
3.POSIX
POSIX是可移植的UNIX操作系统接口(Portable Operating System Interface of UNIX)的缩写,其由IEEE(Institute of Electrical and Electronic Engineering)所开发,由ANSI和ISO标准化。
POSIX的最初开发目的是为了提高 UNIX 环境下应用程序的可移植性,但是随着其发展,POSIX现在并不局限于 UNIX环境,许多其他的操作系统,包括Linux和Windows,也支持POSIX的部分或者全部。
4.ISO C
C语言是由Dennis M. Ritchie在1973年设计和实现的,并且在1978年通过《The C Programming Language》一书将C语言推向全世界。
美国国家标准局(ANSI)在1988年10月颁布ANSI标准X3.159-1989(即ANSI C标准)),随后国际标准(ISO)在1989年左右采纳 ANSI C标准,并且将其定义为ISO/IEC 9899:1990,这就是ISO C。
随着计算机技术的不断发展,ISO C的版本号也在随之发展,到目前为止最新的ISO C版本号是ISO/IEC 9899:1999,也就是C99。