轻松一下——优化文件系统
偶尔,在C和UNIX中,有些方面是令人感觉相当轻松的。只要出发点合理,什么样的奇思妙想都不为过。IBM/Motorola/Apple PowerPC架构具有一种E.I.E.I.O指令[1],代表“Enforce In-Order Execution of I/O”(在I/O中实行按顺序执行的方针)。与这种思想相类似,在UNIX中也有一条称作tunefs的命令,高级系统管理员用它修改文件系统的动态参数,并优化磁盘中文件块的布局。
和其他的Berkeley[2]命令一样,在早期的tunefs在线手册上,也是以一个标题为“Bugs”的小节来结尾。内容如下:
Bugs:
这个程序本来应该在安装好的(mounted)和活动的文件系统上运行,但事实上并非如此。因为超级块(superblock)并不是保持在高速缓冲区中,所以只有当该程序运行在未安装好的(dismounted)文件系统中时才有效。如果运行于根文件系统,系统必须重新启动。
你可以优化一个文件系统,但不能优化一条鱼。
更有甚者,在文字处理器的源文件中有一条关于它的注释,警告任何人不得忽视上面这段话!内容如下:
如果忽视这段话,你就等着烦吧。一个UNIX里的怪物会不断地纠缠你,直到你受不了为止。
当SUN和其他一些公司转到SVr4 UNIX平台时,我们就看不到这条警告了。在SVr4的手册中也没有了“Bugs”这一节,而是改名为“注意”。(会不会误导大家?)“优化一条鱼”这样的妙语也不见了。作出这个修改的人现在一定在受UNIX里面怪物的纠缠,自作自受!
编程挑战
计算机日期
关于time_t,什么时候它会到达尽头,重新回到开始呢?
写一个程序,找出答案。
1.查看一下time_t的定义,它位于文件/user/include/time.h中。
2.编写代码,在一个类型为time_t的变量中存放time_t的最大值,然后把它传递给ctime()函数,转换成ASCII字符串并打印出来。注意ctime()函数同C语言并没有任何关系,它只表示“转换时间”。
如果程序设计者去掉了程序的注释,那么多少年以后,他不得不担心该程序会在UNIX平台上溢出。请修改程序,找出答案。
1.调用time()获得当前的时间。
2.调用difftime()获得当前时间和time_t所能表示的最大时间值之间的差值(以秒计算)。
3.把这个值格式化为年、月、周、日、小时、分钟的形式,并打印出来。
它是不是比一般人的寿命还要长?
解决方案
计算机日期
这个练习的结果在不同的PC和UNIX系统上有所差异,而且它还与time_t的存储形式有关。在Sun系统中,time_t是long的typedef形式。我们所尝试的第一个解决方案如下:
#include <stdio.h>
#include <time.h>
int main() {
time_t biggest= 0x7FFFFFFF;
printf("biggest = %s \n", ctime(&biggest));
return 0;
}
这是一个输出结果:
biggest = Mon Jan 18 19:14:07 2038
显然,这不是正确的结果。ctime()函数把参数转换为当地时间,它跟世界统一时间UTC(格林尼治时间)并不一致,取决于你所在的时区。本书写作地是加利福尼亚,比伦敦晚8小时,而且现在的年份跟最大时间值的年份相差甚远。
事实上,我们应该采用gmtime()函数来取得最大的UTC时间值。这个函数并不返回一个可打印的字符串,所以不得不用asctime()函数来获取一个这样的字符串。权衡各方面情况后,修订过的程序如下:
#include<stdio.h>
#include<time.h>
int main() {
time_t biggest = 0x7FFFFFFF;
printf("biggest = %s \n", asctime(gmtime(&biggest)));
return 0;
}
它给出了如下的结果:
biggest = Tue Jan 19 03:14:07 2038
看!这样就挤出了8小时。
但是,我们并未大功告成。如果你采用的是新西兰的时区,就会又多出13小时,前提是新西兰在2038年仍然采用夏令时。新西兰在1月时采用的是夏令时(因为位于南半球)。但是,由于新西兰的最东端位于日界线的东面,在那里它应该比格林尼治时间晚10小时而不是早14小时。这样,新西兰由于其独特的地理位置,不幸成为该程序的第一个Bug的受害者。
即使像这样简单的问题也可能在软件中潜藏令人吃惊的隐患。如果有人觉得对日期进行编程是小菜一碟,一次动手便可轻松搞定,那么他肯定没有深入研究问题,程序的质量也可想而知。
[1] 可能是由一个名叫McDonald的老农设计的。
[2]加州大学伯克利分校,UNIX系统的许多版本都是在那里设计的。——译者注