王朝网络
分享
 
 
 

《Code Reading》学习笔记(二)

王朝other·作者佚名  2006-01-09
宽屏版  字体: |||超大  

此书基本上以开源项目 NetBSD 的源码为例,因为笔者认为在类 Unix 系统中 NetBSD 强调了设计的正确性和代码书写的合理性。

让我们从第二章开始吧,先来看一个完整的程序。

以 Unix 系统中一个简单但是很有用的程序 echo 来看, 此程序会在标准输出设备(屏幕)输出它的参数,常被用来向用户显示如下信息:

echo "Cool! Let 's get to it..."

下面是程序代码,如你所看到的,一半以上的代码表示诸如版权、许可信息和程序版本等法律和管理信息。在一个大型有组织的系统里这样的信息必不可少。

C 和 C++ 要正确使用库函数就需要包含头文件。库文档通常会列出每个函数需要的头文件。

标准 C、C++ 和 Java 程序从函数 main 开始执行。 第一次观察一个程序从 main 下手是一个不错的开始。注意有些操作系统例如Microsoft Windows、Java applet 和 servlet hosts, palmtop PCs, 还有嵌入式系统可能使用另一个函数做为程序的入口点,例如 WinMain 或者 init。

C/C++ 程序中 main 函数的两个参数(通常名为 argc 和 argv)用来从操作系统中传递关于指定命令行参数的信息到程序.argc 变量包含了程序参数的数量,argv 是一个包含所有实际参数的字符串数组(在位置 0 包含了程序名)。argv 数组以一个NULL 元素结束,可以以两种不同的方式来处理参数:根据 argc计数或者通过遍历 argv 并将每个元素和 NULL 作比较。在 Java 程序中你会发现 argv 字符串数组和它的 length 方法用来实现同一个目的,然而在 Perl 代码中同样的架构会是@ARGV 数组和$#ARGV 标量。

Figure 2.1 Unix 中的 echo 程序

/*

* Copyright (c) 1989, 1993

* The Regents of the University of California. All rights reserved.

*

* Redistribution and use in source and binary forms, with or without

* modification, are permitted provided that the following conditions

* are met:

* 1. Redistributions of source code must retain the above copyright

* notice, this list of conditions and the following disclaimer.

* 2. Redistributions in binary form must reproduce the above copyright

* notice, this list of conditions and the following disclaimer in the

* documentation and/or other materials provided with the distribution.

* 3. All advertising materials mentioning features or use of this software

* must display the following acknowledgement:

* This product includes software developed by the University of

* California, Berkeley and its contributors.

* 4. Neither the name of the University nor the names of its contributors

* may be used to endorse or promote products derived from this software

* without specific prior written permission.

*

* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND

* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE

* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS

* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

* SUCH DAMAGE.

*/

#include <sys/cdefs.h>

<-- a

#ifndef lint

__COPYRIGHT(

"@(#) Copyright (c) 1989, 1993\n The Regents of the University of California. All rights reserved.\n");

__RCSID("$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $");

#endif /* not lint */

#include <stdio.h> <-- b

#include <stdlib.h> <-- c

#include <string.h> <-- d

int main __P((int, char *[])); <-- e

int

main(argc, argv)

int argc;

char *argv[];

{

int nflag;

/* This utility may NOT do getopt(3) option parsing. */

if (*++argv && !strcmp(*argv, "-n") ) {

++argv;

nflag = 1;

}

else

nflag = 0;

while (*argv) } <-- f

(void)printf("%s", *argv);

if (*++argv) <-- g

putchar(' '); <-- h

}

if (!nflag) <-- i

putchar('\n');

exit(0); <-- j

}

注释 (版权和发布许可), 编译器会忽略的内容。

(a) 在可执行文件中会以字符串出现的版权和程序版本标识

包含以下函数的标准函数库头文件:

(b) printf

(c) exit

(d) strcmp

(e) 用来为早期的编译器隐藏参数的函数声明

程序以此函数开始

此程序的参数数量

实际上的参数(以程序名开始,以 NULL 结束)

此参数为真时输出不会以换行结束

第一个参数是 -n

跳过参数并设置 nflag

(f) 存在要处理的参数

输出参数

(g) 还有下一个参数吗? (前进到 argv 的下一个位置)

(h) 输出用来分隔的空格

(i) 如果 -n 不给定的话以换行结束输出

(j) 表示成功退出程序

此例中 argc 和 argv 的声明有点不常见。C/C++ 中典型的 main 的声明是:

int

main(int argc, char **argv)

相应的 Java 类方法定义是

public static void main(String args[]) {

当你观察一个命令行程序时你会发现处理参数的方法要么使用手工代码要么,在 POSIX 环境中,使用getopt 函数。Java 程序为了同样的目的可能会使用 GNU gnu.getopt 包。

http://www.gnu.org/software/java/packages.html

echo 命令的标准定义并不适用于 getopt 行为; 因此,指定输出不以换行结束的单-n 参数通过手工代码来处理。 前进到 argv 中 echo 第一个参数的位置 (要记得 0 位置保存的是程序名) 并检验是否有此参数存在以开始比较。 此时 strcmp 才被调用将参数和 Null 对比。 先检查参数是否有效,然后使用此参数,融合布尔 AND (&&) 操作符的使用是一种常见的用法。 因为如果左边的运算式是错误的&& 操作符就不会再去计算右边的计算式。如果调用strcmp或者其它的字符串函数,并传给它一个NULL 值而不是指向真实字符数据的指针的话,在许多操作环境中会导致程序崩溃。

注意strcmp 用来比较字符串相等性时返回的非直观值。相等时返回 0,C语言中的 false 值。因此你会看到很多 C 会定义一个宏 STREQ ,当两字符串相等时用来返回 true。

#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)

幸运的是 Java 中 equals 方法的结果直观的多:

if (isConfig) {

configFile = args[i];

isConfig = false;

} else if (args[i].equals("-config")) {

isConfig = true;

} else if (args[i].equals("-debug")) {

debug = true;

} else if (args[i].equals("-nonaming")) {

同时如上表示,读代码时可以将一个级联的 if-else if-...-else 序列做为一个互相排斥的几选一来看。

程序中循环访问所有剩下的参数并将它们以空格字符分隔输出的部分相对来说比较直白。

以换行结束输出后,echo 调用表示成功(0)的 exit 来结束程序。

需要此书的朋友可以留下E-mail,英文版,1,98M

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有