花絮
维修“专家”
一所知名大学的一位系统管理员责任维护几百台DEC的运行。他很快学会诊断机器的故障,并能指出那块主板出了问题。为了稳定地获得那些少见设备的补给,他还必须要定购一些维修服务。定购的这些服务包括:DEC的代表需亲临机房,诊断并找出哪块主板出了问题,然而将其替换。而实际上,大学的员工有着严格的纪律,不可让DEC接触这些DEC。
一种典型的服务是打电话给数字设备公司,告诉他哪个部件坏了,他们派代表来管理,找到出问题的部件,然后换上一块好的部件。代表们不再运行一些诊断程序或其他测试工作,这些工作都是事先为他们做好了的。
多年以后, DEC公司创立一个“精简人员”计划。该计划准备为客户培养一些技工,在关键的时候,由为客户培养的这些人来找出出错的板子,并从DEC公司换取新的主板。这当然适合于该大学,因为他们已经那样做了多年。
这个计划要求客户人员必须举办一个培训班,讲述怎样诊断系统错误。那位系统管理人员肯定会对这种班欣然接受。他们也需要度假。实际上在前两天上课的时间里,他一直睡觉。第3天再进入到实验室开始工作。教师使用了3台机器,学生们被分为不同的小组,假定要花费一个上午来查找哪个机器出了问题。
我们的勇士这时候启动他的机器,看了一眼他机器上闪烁的指示灯,便这样告诉大家: “硬盘卡坏了!”
教师有点吃惊:“您是怎么知道的?”
“硬盘指示灯闪烁不正常!”
这位管理员来到下一台机器边,看了一下说 “内存接口卡坏了!”来到下一台机器边:“处理器坏了!”
3台机器看完了。这个本来的计划是让3个组花费一个上午的时间。而这个家伙总共只花费了2分钟(我事后和他闲聊,他告诉我,如果知道有人在计时,他会干得更快)。
老师于是来到本用于下午教学的机器旁。这台机器是在实际场景中经过特殊的设置,有一个真正难于发现(几乎不可能发现)的问题。
老师知道这个问题不能通过观察指示灯来发现,于是他想看看这个勇士会怎样处理。这个家伙打开机器的后盖,甚至在他打开用于指示主板状况的“ON”开关之前,就认定:“这个主板出了故障,芯片U18坏了。这将不时地导致数据线的奇偶校验出错!”
这时,老师意识到这个学生非常优秀,但他如何能不打开机器就发现那一块主板出了问题。这不可能!
“您怎么知道它坏了?”老师问。
管理员指向着芯片的角上一个蓝色小标签说:“看那是什么?我为了保证数字设备公司不至于换回我自己的板子,贴上了这样的一个小标签。这个板子是我们大学的。我就是那个最初发现这个问题,并将其反馈给DEC公司的在线服务部门的那个人。”
本来设计为一个上午和下午的问题现在却在大约十分钟之内就得到了解决。于是老师决定让这个班可以出去吃比萨饼和喝啤酒了。
4.27 程序53:最大值混乱
最大值函数是简单的,测试代码也很简单,答案也应很简单。那么,就请找出下文中的bug。
1 /************************************************
2 * test_max -- Test the max function. ?*
3 ************************************************/
4 #include <iostream>
5
6 /************************************************
7 * max -- return the larger of two integers. ?*
8 * ?? *
9 * Returns: ?*
10 * biggest of the two numbers. ?*
11 ************************************************/
12 const int &max(
13 const int &i1, // A number
14 const int &i2 // Another number
15 )
16 {
17 if (i1 > i2)
18 return (i1);
19 return (i2);
20 }
21
22 int main()
23 {
24 // I is the biggest of the two expression
25 const int &i = max(1+2, 3+4);
26
27 std::cout <<
28 "The biggest expression is " <<
29 i << std::endl;
30
31 return (0);
32 }
(请参见“提示289”和“答案22”)
花絮
人无完人:为了真正消除bug,您需要的是计算机。
4.28 程序54:从深层开始
这段程序为什么会导致内存泄漏呢?
1 /************************************************
2 * Combine strings with a variable length ? *
3 * string class. ? *
4 ************************************************/
5 #include <setjmp.h>
6 #include <iostream>
7 #include <cstring>
8
9 // Place to store jump information
10 static jmp_buf top_level;
11
12 // Longest string combination allowed.
13 static const unsigned int MAX_LENGTH = 30;
14
15 /***********************************************
16 * combine -- Combine two strings with ? *
17 * limit checking ? *
18 ***********************************************/
19 static std::string combine(
20 const std::string &first, // First string
21 const std::string &second // Second string
22 )
23 {
24 // Strings put together
25 std::string together = first + second;
26
27 if (together.length() > MAX_LENGTH) {
28 longjmp(top_level, 5);
29 }
30 return (together);
31 }
32
33 int main()
34 {
35 std::string first("First ");
36 int i;
37
38 for (i = 0; i < 10; i++) {
39
40 // Save our place
41 if (setjmp(top_level) == 0)
42 {
43 first = combine(first,
44 std::string("second "));
45 } else {
46 std::cout <<
47 "Length limit exceeded\n";
48 break;
49 }
50 }
51 return (0);
52 }
(请参见“提示146”和“答案66”)
4.29 程序55:羊群计数程序
Farmer Brown是一个牧羊人,他有一个邻居只需要看一眼羊群就知道羊群共有多少只羊。Farmer Brown很奇怪这个朋友的这种奇特功能,于是问道:“Ian,您怎么这么快就能知道有多少羊?”
“很简单!” Ian回答到:“我只数一下有多少条羊腿,然后除以4就行了!”
Farmer Brown对这件事的映象特别深,于是他写了一小段C++程序来验证Ian给羊计数的算法。然而这段程序不却能处理大型羊群的问题。为什么呢?
1 /************************************************
2 * sheep -- Count sheep by counting the ? *
3 * number of legs and dividing by 4. ? *
4 ************************************************/
5 #include <iostream>
6
7 /*
8 * The number of legs in some different
9 * size herds.
10 */
11 const short int small_herd = 100;
12 const short int medium_herd = 1000;
13 const short int large_herd = 10000;
14
15 /***********************************************
16 * report_sheep -- Given the number of legs, ? *
17 * tell us how many sheep we have. ? *
18 ***********************************************/
19 static void report_sheep(
20 const short int legs // Number of legs
21 )
22 {
23 std::cout <<
24 "The number of sheep is: " <<
25 (legs/4) << std::endl;
26 }
27
28 int main() {
29 report_sheep(small_herd*4); // Expect 100
30 report_sheep(medium_herd*4); // Expect 1000
31 report_sheep(large_herd*4); // Expect 10000
32 return (0);
33 }
(请参见“提示165”和“答案1”)
4.30 程序56:程序的魔法失效
下面这段程序设计的目的是看看两个目录中的两个文件中是否包含同一个魔法数字。在我们的示例中,有以下两个文件:
first/first
second/second
这两个文件都包含一个魔法数字。
但是这个程序会输出什么呢?为什么?
1 /************************************************
2 * scan_dir -- Scan directories for magic files ? *
3 * and report the results. ? *
4 * ? *
5 * Test on the directories "first" and "second".
? *
6 ************************************************/
7 #include <iostream>
8 #include <dirent.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 const long int MAGIC = 0x464c457f; // Linux executable
magic #
12 /************************************************
13 * next_file -- find a list of files with magic ? *
14 * numbers that match the given number. ? *
15 * ? *
16 * Returns the name of the file or ? *
17 * NULL if no more files. ? *
18 ************************************************/
19 char *next_file(
20 DIR *dir // Directory to scan
21 ) {
22 // Current entry in the dir
23 struct dirent *cur_ent;
24
25 while (1) {
26
27 cur_ent = readdir(dir);
28 if (cur_ent == NULL)
29 return (NULL);
30
31 int fd = open(cur_ent->d_name, O_RDONLY);
32 if (fd < 0) {
33 // Can't get the file so try again
34 continue;
35 }
36
37 int magic; // The file's magic number
38
39 // Size of the header read
40 int read_size =
41 read(fd, &magic, sizeof(magic));
42
43 if (read_size != sizeof(magic)) {
44 close(fd);
45 continue;
46 }
47
48 if (magic == MAGIC) {
49 close(fd);
50 return (cur_ent->d_name);
51 }
52 close(fd);
53 }
54 }
55 /************************************************
56 * scan_dir -- Scan a directory for the files ? *
57 * we want. ? *
58 ************************************************/
59 char *scan_dir(
60 const char dir_name[] // Directory name to use
61 ) {
62 // Directory to scan
63 DIR *dir_info = opendir(dir_name);
64 if (dir_info == NULL)
65 return (NULL);
66
67 chdir(dir_name);
68
69 // Name of the file we just found
70 char *name = next_file(dir_info);
71 closedir(dir_info);
72
73 chdir(".."); // Undo the original chdir
74
75 return (name);
76 }
77
78 int main() {
79 // Find a file in the directory "first"
80 char *first_ptr = scan_dir("first");
81
82 // Find a file in the directory "second"
83 char *second_ptr = scan_dir("second");
84
85 // Print the information about the dir first
86 if (first_ptr == NULL) {
87 std::cout << "First: NULL ";
88 } else {
89 std::cout << "First: " << first_ptr
<< " ";
90 }
91 std::cout << '\n';
92
93 // Print the information about the dir second
94 if (second_ptr == NULL) {
95 std::cout << "Second: NULL ";
96 } else {
97 std::cout << "Second: " << second_ptr
<< " ";
98 }
99 std::cout << '\n';
100 return (0);
101 }
(请参见“提示86”和“答案100”)
|