第一次网上买书

也许有人会笑话我,但这是事实,前天我才收到我第一次网购的两本书。在这个互联网发达的年代,这个"第一次"未免有些落伍了。其实不在网上买书也是有原因的,现在的书店也是打折很多的,还有很多与公司有协议的,拿着工卡就打更多折扣,特别是计算机图书,社科类的书倒是没有这么大折扣。

这次是从互动出版网(china-pub)买的书。互通出版网成立于2000年7月,我也是那个时间进入大学学习并开始接触计算机和网络的,我也是那时注册的出版网的会员的,也许还属于从未买过书的元老级会员呢。

在大上周日,在网上发现china-pub的"Algorithm in C"这本书的英文版居然6折出售,要知道这本书在书店基本已经绝迹了。顿时产生了网购的念头。网购一单买一本是不划算的,再寻觅一本吧。在数学书店中,我发现了排在销售榜第一位的"什么是数学"一书,我一直以来都想买一本科普性质的数学书。而"什么是数学"恰是一本科普性质的,但是也不乏深度的书,属于数学爱好者和专业人员皆宜的书。这本书第一版诞生
于上个世纪中旬,几十年来一直长盛不衰,已经成为世界公认的经典数学科普读物了。该书第一版作者R·柯朗(Richard Courant)是20世纪杰出的数学家,他的"数学物理方程"和"微积分学"也是学科内公认的杰出代表作。相信看这样大师做的书一定是会有思想性的收获的,关键是能坚持读下去,估计有一定难度,呵呵。拿下。另外还有两本著名数学科普书"从一到无穷大:科学中的事实和臆测"和"啊哈,灵机一动"也是值得收入囊中的,下次吧,书要一本一本看,贪多嚼不烂啊。

C算法"Algorithm in C"这本书也是不错的,被作为美国很多名校的CS专业教材或参考资料,书中以介绍和实践为主,并不是教你如何进行算法设计的书(千万别买错了),但平时放一本这样的书在身边,可以作为参考书使用。

面对'错误'的抉择

大凡写程序者,都会遇到错误;
大凡写程序者也都知道两种错误处理的机制:传统的'错误码返回机制'和'面向对象语言引入的异常处理机制'。

人们常常会在这两种机制之间徘徊不定,难以抉择。但有两类人大可不必为此头痛,他们是坚决只使用'错误码返回机制'的人,和坚决只使用'异常处理机制'的人。而苦就苦了摇摆在中间,思索不定的那些人了。这群人有一个特点就是不停的问:"什么是异常?什么时候该使用错误码返回?什么时候又要用标准的异常处理机制呢?内存不足是不是异常?网络瘫痪是不是异常?用户输入id的超出了允许的长度该如何处理?"等
等诸如此类的问题。

我一直使用C,C没有像C++、Java、Ruby那样提供标准的异常处理机制,C只是提供了setjmp和longjmp这样的粗糙的甚至让很多新人觉得迷惑的调用接口,所以到目前为止,我还没有真正用过"异常处理"来写过代码。直到我看到"David Hanson "的"c interfaces and implementations(C语言接口与实现)"中第4章封装的C的异常处理宏。看完后我有些迷惑。迷惑的不是这组宏有什么精湛技艺,而是他破坏了以前我对错误处理的单一使用错误码返回的想法,他又给了我一个选择:使用异常处理。而多了一种选择之后,我也陷入徘徊不定中。只能反复的一遍又一遍的看和回味Hanson在这章起始的那段关于错误分类的描述和理解,以寻求在返回错误码和使用异常处理之间的平衡。

Hanson将错误分为三类:
用户错误,就是由用户的不正确输入引起的,对于此类错误的态度是:函数必须处理错误并返回错误代码。
//testusererr.c
int main(int argc, char *argv[]) {
if (argc <= 1) {
printf("you should input at leaset an argument!\n");
return 1;
}

int i = atoi(argv[1]);

if (i < 5) {
printf("i should be more than 5.\n");
return 2;
}

return 0;
}

上述的例子仅是一个程序接收用户的输入,并对其输入错误进行处理。

那么对于一个功能接口而言,对其参数是否都要做类似处理呢?通常来说在我们系统中除了针对用户的接口需要进行外,其他的接口都是内部调用的,比如库,库提供了接口同时也隐含了某种约定。我们作为程序员在使用库的时候都会遵守约定。但是这是不是这些库接口就不用对其接口参数进行任何处理了呢。一般我们会在接口的入口处加上断言。这就是我们要说的第二种错误–可检查的运行时错误。

按照Hanson的说法,可检查的运行时错误不是用户错误,上面已经说了,程序员已经按照约定传入了适当的参数,那么一旦出现错误,这个错误是从何而来的呢?可检查的运行时错误恰恰是揭示了程序的漏洞,他们不可预料,通常遇到此类错误,应用程序一般将无法恢复。看下面的例子:

//testcheckedrterr.c
#include
#include

#define MY_MAGIC 0×19210723

struct Foo {
int i;
char id[22];
#ifdef _DEBUG
unsigned int magic;
#endif

};

void check_foo(const struct Foo *foo) {
assert(foo != NULL);
#ifdef _DEBUG
assert(foo->magic == MY_MAGIC);
#endif
;
}

int main() {
struct Foo foo;
foo.i = 13;
#ifdef _DEBUG
foo.magic = MY_MAGIC;
#endif
strcpy(foo.id, "this will cause an overflow");

check_foo(&foo);
}

gcc -D_DEBUG -g *.c
执行的结果:
Assertion failed: foo->magic == MY_MAGIC, file testcheckedrterr.c, line 20
退出 ((主存储器)信息转储)

这里程序的确是按照check_foo的需要的参数提供了参数,只是没有预料到,程序存在栈溢出,对于这种运行时错误,在check_foo中我们使用了断言。断言一般都是无法恢复的,直接的结果就是程序退出。

异常,第三类错误,极少出现,可能不可预测,但有可能从中恢复的错误。如:内存不足、网络瘫痪、磁盘空间满等。按照Hanson的经验,由于异常发生很少,很多可能发生此类异常的函数都是没有返回值的。这时是采用异常处理机制的好时机。

说到这,也许还只是停留在说教上,也许开头提到的那些疑问仍然无法回答。我想什么样的回答都不能令所有人满意,自己在项目中摸索理解吧。其实永远没有绝对的事情,你大可在程序中丝毫不考虑使用异常机制。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats