第
1章 Linux
下
C
语言编程简介
本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等。通过本章的学习,可以对在Linux下使用C语言编程有一个基本的了解。
1.1 Linux
简
介
Linux是能够自由传播并继承了UNIX内核的操作系统,是对UNIX的简化和改进,它既保留了UNIX系统的高安全性,同时也使其操作更加简单方便,从而使单机用户也可以使用。UNIX内核指的是操作系统底层的核心程序代码。
因为 Linux本身脱胎于UNIX系统,所以Linux程序与UNIX程序是十分相似的。事实上,UNIX下编写的各种程序基本上都可以在 Linux下编译和运行。此外,许多在UNIX操作系统下创建的一些商业化应用软件,其二进制形式几乎可以在不作任何修改的情况下直接运行在 Linux系统上。
Linux是由芬兰的赫尔辛基大学 (Helsinki)学生Linus Torvalds把Minix 系统向x86移植的结果。当时 Linus 手边有个 Minix 系统(UNIX 的一个分支),他对这个操作系统相当有兴趣,由于当时他正好有一台个人计算机,他想把这个系统移植到该计算机(x86 架构)上来使用。由于受益于Stallman提倡的开放源代码(Open Source)思想,他得以接触到UNIX操作系统的一些源代码,并仔细研读了UNIX 的核心,然后去除较为繁复的核心程序,将它改写成能够适用于一般个人计算机的一种操作系统,即Linux系统的雏形。
1992年1月,大概只有100人开始使用Linux,但他们为Linux的发展壮大作出了巨大贡献。他们对一些不合理的代码进行了改进,修补了代码错误并上传补丁。Linux的腾飞最关键的因素是获得了自由软件基金(FSF)的支持,他们制定了一个GNU计划,该计划的目标就是要编写一个完全免费的 UNIX版本
——包括内核及所有相关的组件,可以让用户自由共享并且改写软件,而Linux正好符合他们的意愿。他们将Linux与其现有的GNU应用软件很好地结合起来,使Linux拥有了图形用户界面。
提示:
Linux 实际上只是提供了操作系统的内核;它实现了多任务和多用户功能,管理硬件,分配内存,激活应用程序的运行。对初学者来说,最重要的是要明白奇数的内核版本(比如 2.3、2.5、2.7)是实验用的、正在开发的内核。 稳定的、正式发行的内核版本号则是偶数的(比如 2.2、2.4、2.6)。
1994年3月, Linux 1.0正式版发布,它的出现无异于网络的“自由宣言”。从此Linux用户迅速增加,Linux的核心开发小组也日渐强大。在Linux所包含的数千个文件中,有一个名为Credits的文件,里面列出了100多名对Linux有过重要贡献的黑客,包括他们的名字、地址以及所做的工作。其中的软件都是经过“优胜劣汰”的达尔文式的选择方式保存下来的。Linux的发展方法看起来很简单:所有黑客都可为其添加额外功能并完善其性能。所谓的β测试也不仅是修补漏洞,而是进行集成并进行更多的改进、创新。Linux发展过程中的这种随意性,造成了发展过程中出现了各种各样的Linux版本。
提示:
β测试是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。这些用户是与公司签定了支持产品预发行合同的外部客户,他们要求使用该产品,并愿意返回有关错误信息给开发者。开发者通常不在测试现场,因而,β测试是在开发者无法控制的环境下进行的软件现场应用。在β测试中,由用户记下遇到的所有问题,包括真实的以及主观认定的,定期向开发者报告,开发者在综合用户的报告之后,作出修改,最终将软件产品交付给全体用户使用。由于它处在整个测试的最后阶段,因此不能指望这时发现主要问题。同时,产品的所有手册文本也应该在此阶段完全定稿。
Linux操作系统在短短的几年之内得到了非常迅猛的发展,这与Linux具有的良好特性是分不开的。Linux几乎包含了UNIX的全部功能和特性,同时又有自己的一些特点。概括地讲,Linux具有以下主要特性:
●
开放性
开放性是指系统遵循世界标准规范,特别是遵循开放系统互联(OSI)国际标准。凡遵循国际标准所开发的硬件和软件,都能彼此兼容,可方便地实现互联。
●
多用户
多用户是指系统资源可以被不同用户各自拥有和使用,即每个用户对自己的资源(例如:文件、设备)有特定的权限,互不影响。Linux继承了UNIX的多用户特性。
●
多任务
多任务是现代计算机的最主要的一个特点。它是指计算机同时执行多个程序,而且各个程序的运行互相独立。Linux系统调度每一个进程,平等地访问微处理器。由于CPU的处理速度非常快,其结果是,启动的应用程序看起来好像在并行运行。事实上,从处理器执行一个应用程序中的一组指令到Linux调度微处理器再次运行这个程序之间只有很短的时间延迟,用户是感觉不出来的。
●
良好的用户界面
Linux向用户提供了3种界面:传统操作界面、系统调用界面和图形用户界面。Linux的传统操作界面是基于文本的命令行界面,即Shell,它既可以联机使用,又可在文件上脱机使用。Shell有很强的程序设计能力,用户可方便地用它编制程序,从而为用户扩充系统功能提供了更高级的手段。可编程Shell是指将多条命令组合在一起,形成一个Shell程序,这个程序可以单独运行,也可以与其他程序同时运行。
系统调用界面是为用户提供编程时使用的界面。用户可以在编程时直接使用系统提供的系统调用命令。系统通过这个界面为用户程序提供低级、高效率的服务。
Linux还为用户提供了图形用户界面。它利用鼠标、菜单、窗口、滚动条等设施,给用户呈现一个直观、易操作、交互性强的友好的图形化界面。
●
设备独立性
Linux是具有设备独立性的操作系统,它的内核具有高度的适应能力。随着越来越多的程序员开发Linux系统,将会有更多的硬件设备加入到各种Linux内核和发行版本中。另外,由于用户可以免费得到Linux的内核源代码,因此,用户可以根据需要修改内核源代码,以便适应新增加的外部设备。
设备独立性是指操作系统把所有外部设备统一当作文件来看待,只要安装它们的驱动程序,任何用户都可以像使用文件一样,操纵、使用这些设备,而不必知道它们的具体存在形式。
具有设备独立性的操作系统,通过把每一个外围设备看作一个独立文件来简化增加新设备的工作。当需要增加新设备时,系统管理员就在内核中增加必要的连接。这种连接(也称作设备驱动程序)能保证每次调用设备提供的服务时,内核能以相同的方式来处理它们。当新的或更好的外设被开发并交付给用户时,系统允许在这些设备连接到内核后,能不受限制地立即访问它们。设备独立性的关键在于内核的适应能力。其他操作系统只允许一定数量或一定种类的外部设备连接。而设备独立性的操作系统却能够容纳任意种类及任意数量的设备,因为每一个设备都是通过其与内核的专用连接进行独立访问的。
●
提供了丰富的网络功能
完善的内置网络是Linux的一大特点。Linux在通信和网络功能方面优于其他操作系统。其他操作系统不包含如此紧密地和内核结合在一起的连接网络的能力,也没有内置这些联网特性的灵活性。而Linux为用户提供了完善的、强大的网络功能。
支持Internet是其网络功能之一。Linux免费提供了大量支持Internet的软件,通过Internet,用户能用Linux与世界上各个地区的人方便地通信。它内建了http、ftp、dns等功能,支持所有常见的网络服务,包括ftp、telnet、NFS、TCP、IP等,加上超强的稳定性,因此很多ISP(Internet Service Providers)都是采用Linux来架设邮件服务器、FTP服务器及Web 服务器等各种服务器的。Linux在最新发展的内核中还包含了一些通用的网络协议,比如IPv4、IPv6、AX.25、X.25、IPX、DDP(Appletalk)、NetBEUI、Netrom 等。用户能通过一些Linux命令完成内部信息或文件的传输。 Linux不仅允许进行文件和程序的传输,它还为系统管理员和技术人员提供了访问其他系统的接口。
另外,还可以进行远程访问。通过这种远程访问的功能,一位技术人员能够有效地为多个系统服务,即使那些系统位于相距很远的地方。稳定的核心中目前包含的网络协议有TCP、IPv4、IPX、DDP、AX等。另外还提供Netware的客户机和服务器,以及现在最热门的Samba(让用户共享Mircosoft Network资源)。
●
可靠的系统安全
Linux采取了许多安全技术措施,包括对读/写进行权限控制、带保护的子系统、审计跟踪、核心授权等,这为网络多用户环境中的用户提供了必要的安全保障。
●
良好的可移植性
可移植性是指将操作系统从一个平台转移到另一个平台上,并使它仍然能按其自身的方式运行的能力。
Linux是一种可移植的操作系统,能够在从微型计算机到大型计算机的任何环境中运行。可移植性为运行Linux的不同计算机平台与其他任何计算机进行准确而有效的通信提供了手段,不需要另外增加特殊的和昂贵的通信接口。
1.2 C
语言的简介和特点
C语言是贝尔实验室的Dennis Ritchie在B语言的基础上开发出来的,1972年在一台DEC PDP-11计算机上实现了最初的C语言。C语言是与硬件无关的,用C语言编写的程序能移植到大多数计算机上。C语言在各种计算机上的快速推广导致了许多C语言版本。这些版本虽然是类似的,但通常是不兼容的。为了明确定义与机器无关的C语言,1989年美国国家标准协会制定了C语言的标准(ANSI C)。在ANSI标准化后,C语言的标准在相当长的一段时间内都基本保持不变,尽管C++进行了改进(实际上,Normative Amendment1在1995年已经开发了一个新的C语言版本,但是这个版本很少为人所知)。ANSI标准在20世纪90年代又经历了一次比较大的改进,这就是ISO9899:1999(1999年出版)。这个版本就是通常提及的C99。它被ANSI于2000年2月采用。
C 语言之所以发展迅速,而且成为最受欢迎的语言之一,主要是因为它具有强大的功能。许多著名的系统软件,如UNIX/Linux、Windows、DBASE Ⅲ PLUS、DBASE Ⅳ 都是由C 语言编写的。用C 语言加上一些汇编语言子程序,就更能显示C 语言的优势,像PC- DOS 、WORDSTAR等就是用这种方法编写的。
归纳起来,C 语言具有下列特点:
●
中级语言。它把高级语言的基本结构和语句与低级语言的实用性结合起来。C 语言可以像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。
●
结构式语言 。结构式语言的显著特点是代码及数据的模块化,即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便
于使用、维护以及调试。
C
语言是以函数形式提供给用户的,
这些函数可方便地调用,
并采用多种循环、条件语句控制程序流向,从而使程序完全结构化。
●
功能齐全。C 语言具有各种各样的数据类型,并引入了指针概念,可使程序效率更高。另外,C 语言也具有强大的图形功能,支持多种显示器和驱动器。而且计算功能、逻辑判断功能也比较强大,可以实现决策目的。
●
可与Linux无缝结合。Linux本身是使用C语言开发的,在Linux上用C语言作开发,效率很高。
1.3 Linux
程序设计基础知识
对一个Linux开发人员来说,在使用一种编程语言编写程序以前,对操作系统中程序的保存位置有一个透彻的了解是很重要的。比如,应知道软件工具和开发资源保存在什么位置是很重要的。下面首先简单介绍Linux的几个重要的子目录和文件。
这部分内容虽然是针对 Linux的,但同样也适用于其他类UNIX系统。
1.3.1
程序安装目录
Linux下的程序通常都保存在专门的目录里。系统软件可以在/usr/bin子目录里找到。系统管理员为某个特定的主机系统或本地网络添加的程序可以在/usr/local/bin子目录里找到。
系统管理员一般都喜欢使用/usr/local子目录,因为它可以把供应商提供的文件和后来添加的程序以及系统本身提供的程序隔离开来。/usr子目录的这种布局方法在需要对操作系统进行升级的时候非常有用,因为只有/usr/local子目录里的东西需要保留。我们建议读者编译自己的程序时,按照/usr/local子目录的树状结构来安装和访问相应的文件。
某些随后安装的软件都有它们自己的子目录结构,其执行程序也保存在特定的子目录里,最明显的例子就是 X窗口系统,它通常安装在一个名为/usr/X11R6的子目录里,XFree论坛组织发行的用于英特尔处理器芯片的各种XFree 86窗口系统变体也安装在这里。
GNU的C语言编译器gcc(后面的程序设计示例中使用的就是它)通常安装在/usr/bin或者/usr/local/bin子目录里,但通过它运行的各种编译器支持程序一般都保存在另一个位置。这个位置是在用户使用自己的编译器时指定的,随主机类型的不同而不同。对 Linux系统来说,这个位置通常是/usr/lib/gcc-lib/目录下以其版本号确定的某个下级子目录。GN的C/C++编译器的各种编译程序以及GNU专用的头文件都保存在这里。
1.3.2
头文件
在使用C语言和其他语言进行程序设计的时候,我们需要头文件来提供对常数的定义和对系统及库函数调用的声明。对C语言来说,这些头文件几乎永远保存在/usr/include及其下级子目录里。那些赖于所运行的 UNIX或Linux操作系统特定版本的头文件一般可以在/usr/include/sys或/usr/include/linux子目录里找到。其他的程序设计软件也可以有一些预先定义好的声明文件,它们的保存位置可以被相应的编译器自动查找到。比如,X窗口系统的/usr/include/X1R6子目录和GNU C++编译器的/usr/include/g++ -2子目录等。
在调用C语言编译器的时候,可以通过给出“ -I”编译命令标志来引用保存在下级子目录或者非标准位置的头文件,类似命令如下:
[david@localhost linux]$ gcc -I /usr/openwin/include hello.c
该命令会使编译器在/usr/openwin/include子目录和标准安装目录两个位置查找fred.c程序里包含的头文件。具体情况可以参考第3章。
用grep命令来查找含有某些特定定义与函数声明的头文件是很方便的。假设想知道用来返回程序退出状态的文件的名字,可以使用如下方法:
先进入/usr/include子目录,然后在grep命令里给出该名字的几个字母,如下所示:
[david@localhost linux]$ grep KEYSPAN *.h
pci_ids.h:#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9
pci_ids.h:#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334
grep命令会在该子目录里所有名字以.h结尾的文件里查找字符串“KEYSPAN”。在上面的例子里,(从其他文件中间)可以查找到文件pci_ids.h。
1.3.3
库文件
库文件是一些预先编译好的函数的集合,那些函数都是按照可再使用的原则编写的。它们通常由一组互相关联的用来完成某项常见工作的函数构成。比如用来处理屏幕显示情况的函数(curses库)等。我们将在后续章节讲述这些函数库文件。
标准的系统库文件一般保存在/lib或者/usr/lib子目录里。编译时要告诉 C语言编译器(更确切地说是链接程序)应去查找哪些库文件。默认情况下,它只会查找 C语言的标准库文件。这是从计算机速度还很慢、CPU价格还很昂贵的年代遗留下来的问题。在当时,把一个库文件放到标准化子目录里然后寄希望于编译器自己找到它是不实际的。库文件必须遵守一定的命名规则,还必须在命令行上明确地给出来。
库文件的名字永远以lib这几个字母打头,随后是说明函数库情况的部分(比如用c表示这是一个 C语言库;而m表示这是一个数学运算库等)。文件名的最后部分以一个句点(.)开始,然后给出这个库文件的类型,如下所示:
●
.a 传统的静态型函数库。
●
.so和. sa 共享型函数库(见下面的解释)。
函数库一般分为静态和共享两种格式,用ls /usr/lib命令查一下就能看到。在通知编译器查找某个库文件的时候,既可以给出其完整的路径名,也可以使用–l标志。详细内容可以参考第3章。
1. 静态库
函数库最简单的形式就是一组处于可以“拿来就用”状态下的二进制目标代码文件。当有程序需要用到函数库中的某个函数时,就会通过 include语句引用对此函数做出声明的头文件。编译器和链接程序负责把程序代码和库函数结合在一起成为一个独立的可执行程序。如果使用的不是标准的C语言运行库而是某个扩展库,就必须用–l选项指定它。
静态库也叫做档案(archive),它们的文件名按惯例都以. a结尾。比如 C语言标准库为/usr/lib/libc.a、X11库为/usr/X11R6/lib/libX11.a等。
自己建立和维护静态库的工作并不困难,用ar(“建立档案”的意思)程序就可以做到,另外要注意的是,应该用gcc -c命令对函数分别进行编译。应该尽量把函数分别保存到不同的源代码文件里去。如果函数需要存取普通数据,可以把它们放到同一个源代码文件里并使用在其中声明为static类型的变量。
2. 共享库
静态库的缺点是,如果我们在同一时间运行多个程序而它们又都使用着来自同一个函数库里的函数时,内存里就会有许多份同一函数的备份,在程序文件本身也有许多份同样的备份。这会消耗大量宝贵的内存和硬盘空间。
许多UNIX系统支持共享库,它同时克服了在这两方面的无谓消耗。对共享库和它们在不同系统上实现方法的详细讨论超出了本书的范围,所以我们把注意力集中在眼前 Linux环境下的实现方法上。
共享库的存放位置和静态库是一样的,但有着不同的文件后缀。在一个典型的 Linux系统上,C语言标准库的共享版本是 /usr/lib/libc.so N,其中的N是主版本号。
1.4 Linux
下
C
语言编程环境概述
Linux下C语言编程常用的编辑器是vim或emacs,编译器一般用gcc,编译链接程序用make,跟踪调试一般使用gdb,项目管理用makefile。下面先通过一个小程序来熟悉这些工具的基本应用。各个工具的详细使用方法将在后面的各个章节逐步讲解。
(1) 要编辑C源程序,应首先打开vim或emacs编辑器,然后录入以下多段源代码。使用main函数调用mytool1_print、mytool2_print这两个函数。
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
(2) 在mytool1.h中定义mytool1.c的头文件。
/* mytool1.h */
#ifndef_MYTOOL_1_H
#define_MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
(3) 用mytool1.c实现一个简单的打印显示功能。
/* mytool1.c */
#include "mytool1.h"
void mytool1_print(char *print_str)
{
printf("This is mytool1 print %s/n",print_str);
}
(4) 在mytool2.h中定义mytool2.c头文件。
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
(5) mytool2.c实现的功能与mytool1.c相似。
/* mytool2.c */
#include "mytool2.h"
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s/n",print_str);
}
(6)
使用
makefile
文件进行项目管理。
makefile
文件内容如下。
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
(7) 将源程序文件和makefile文件保存在Linux下的同一个文件夹下,然后运行make编译链接程序如下:
[david@localhost 1c]$ make
[david@localhost 1c]$ ./main
This is mytool1 print hello
This is mytool2 print hello
至此,这个小程序算是完成了,如果想跟踪调试可以参考第4章。
1.5 Linux
程序设计的特点
在进行程序设计时首先应养成良好的程序设计风格。Linux操作系统的设计师们鼓励人们采用一种独到的程序设计风格。下面是Linux程序和系统所共有的一些特点。
(1) 简单性。许多最有用的 Linux软件工具都是非常简单的,程序小而易于理解。
(2) 重点性。一个所谓功能齐全的程序可能既不容易使用,也不容易维护。如果程序只用于一个目的,那么当更好的算法或更好的操作界面被开发出来的时候,它就更容易得到改进。在 Linux世界里,通常会在需求出现的时候把小的工具程序组合到一起来完成一项更大的任务,而不是用一个巨大的程序预测一个用户的需求。
(3) 可反复性。使用的程序组件把应用程序的核心部分组建成一个库。带有简单而又灵活的程序设计接口并且文档齐备的函数库能够帮助其他人开发同类的项目,或者能够把这里的技巧用在新的应用领域。例如dbm数据库函数库就是一套由不同功能的函数组成的集合,而不是一个单一的数据库管理系统。
(4) 过滤性。许多Linux应用程序可以用作过滤器,即它们可以把自己的输入转换为另外一种形式的输出。在后面将会讲到,Linux提供的工具程序能够将其他Linux程序组合成相当复杂的应用软件,其组合方法既新颖又奇特。当然,这类程序组合正是由Linux独特的开发方法支撑着的。
(5) 开放性。文件格式比较成功和流行的 Linux程序所使用的配置文件和数据文件都是普通的 ASCII文本。如果在程序开发中遵循该原则,将是一种很好的做法。它使用户能够利用标准的软件工具对配置数据进行改动和搜索,从而开发出新的工具,并通过新的函数对数据文件进行处理。源代码交叉引用检查软件 ctags就是一个这样的好例子,它把程序中的符号位置信息以规则表达式的形式记录下来供检索程序使用。
(6) 灵活性。因为你根本无法预测一个不太聪明的用户会怎样使用你的程序,因此在进行程序设计时,要尽可能地增加灵活性,尽量避免给数据域长度或者记录条数加上限制。同时如果可能,应尽量编写能够响应网络访问的程序,使它既能够跨网络运行又能够在本地单机上运行。
1.6 Linux
下
C
语言编码的风格
Linux作为GN家族的一员,其源代码数以万计,而在阅读这些源代码时我们会发现,不同的源代码的美观程度和编程风格都不尽相同,例如下面的glibc代码:
static voidrelease_libc_mem (void)
{
/*Only call the free function if we still are running in mtrace mode. */
if (mallstream != NULL)
__libc_freeres ();
}
或者Linux的核心代码:
static int do_linuxrc(void * shell)
{
static char *argv[] = { "linuxrc"
,
NULL
,
};
close(0);close(1);close(2);
setsid();
(void) open("/dev/console",O_RDWR,0);
(void) dup(0);
(void) dup(0);
return execve(shell
,
argv
,
envp_init);
}
比较一下,上面的这些代码是否看起来让人赏心悦目?而有些程序员编写的程序由于没有很好的缩进及顺序,让人看起来直皱眉头。编写干净美观的代码,不仅仅使代码更容易阅读,还能使代码成为一件艺术品。与微软的匈牙利命名法一样,Linux上的编程主要有两种编程风格:GNU风格和Linux核心风格,下面将分别介绍。
1.6.1
GNU
编程风格
下面是基于GNU的编程风格,编写代码时应遵循这些基本要求。
●
函数开头的左花括号放到最左边,避免把任何其他的左花括号、左括号或者左方括号放到最左边。
à
尽力避免让两个不同优先级的操作符出现在相同的对齐方式中。
à
每个程序都应该有一段简短地说明其功能的注释开头。例如:fmt - filter for simplefilling of text。
●
请为每个函数书写注释,以说明函数做了些什么,需要哪些种类的参数,参数可能值的含义以及用途。
à
不要在声明多个变量时跨行。在每一行中都以一个新的声明开头。
à
当在一个
if
语句中嵌套了另一个
if-else
语句时,应用花括号把
if-else
括起来。
●
要在同一个声明中同时说明结构标识和变量,或者结构标识和类型定义(typedef)。
à
尽力避免在if的条件中进行赋值。
à
请在名字中使用下划线以分隔单词,尽量使用小写; 把大写字母留给宏和枚举常量,以及根据统一的惯例使用的前缀。
à
命令一个命令行选项时,给出的变量应该在选项含义的说明之后,而不是选项字符之后。
1.6.2
Linux
内核编程风格
下面是 Linux 内核所要求的编程风格:
●
注意缩进格式。
●
将开始的大括号放在一行的最后,而将结束大括号放在一行的第一位。
●
命名系统。变量命名尽量使用简短的名字。
●
函数最好要短小精悍,一个函数最好只作一件事情。
●
注释。注释说明代码的功能,而不是说明其实现原理。
看了上面两种风格的介绍,读者是不是觉得有些太多了,难以记住?不要紧,Linux有很多工具来帮助我们。除了vim和emacs以外,还有一个非常有意思的小工具 indent可以帮我们美化C/C++源代码。
下面用这条命令将Linux 内核编程风格的程序quan.c转变为 GNU编程风格,代码如下:
[david@localhost ~]$ indent -gnu quan.c
利用indent这个工具,大家就可以方便地写出漂亮的代码来。