Learning, Thinking & Researching

shimmer's nest

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  13 随笔 :: 0 文章 :: 10 评论 :: 0 引用

2005年6月11日 #

 

客栈里Guest Book上一个韩国mm写的,copy下来做引子

Top Art R u happy?

Top Art is the best art.

The best art is your happiness.

R u happy?

You are in love.

Your baby is smiling.

You are not hungry anymore.

You are not sad.

You know the world

You know everything.

You are laughing.

You have a job.

You have time.

You are good health.

And….

And….

You are freedom.

You....

You….

Are you happy?

You…..

You…..

Just you create your happness.

Let’s do it.

Do it.

If you want to see the world to laugh, be laughing yourself.

Your smile make the world smiling.

Your happiness can make the world happy.

Your happiness what is it?

What is it?

Just yours…

Top art, r u happy?

 

63        徒步虎跳峡——第一日

700,伴随着手机的嘀嘀声,我们从睡梦中醒来。折腾一番,赶到车站时已经800了。830到桥头的车票还不能出售,只有等到丽江的车发车之前五分钟才有得卖。出了车站正想去觅食,Young却已找到几个欲包车前往桥头的同路人,车票不贵,20¥每人,马上走。顾不得多想了,挤上这辆不大的小面包,车就启程了。看来早餐只能在中途解决了。

一路上的风景不错,司机还兼职了半个向导,给我们指点了沿路的风景。玉龙雪山、哈巴雪山,拉什海,金沙江。据说在冬天会有很多侯鸟飞来拉什海度假,附近也就有很多观鸟的招牌。我们只能在车上遥遥的忘上一眼,想象这湖上停满白鹤的样子。车沿着盘山公路一路蜿蜒,到了半山腰。在我们的一旁是山坡,一旁是峭壁,小城成了落在山谷中的棋盘,这种明朗的色彩在火车上也是常见的,在明媚的阳光照耀下,更见美丽。


远眺拉什海


一路可见金沙江

车上看到的玉龙雪山


车上还有几个同路人,或是唤做驴友吧。打听之后才知道,我身边的是两个香港人,都还是学生。美眉很
pp,白色体恤,扎起来的马尾,总是甜甜的笑着,还有两个浅浅的酒窝,帅哥很健谈,拿着专业的照相机,竟然也是学计算机的小硕。另一人为美国男人,穿着红背心,不高的身材,却有着匀称的身材,健康的肤色。询问了一下香港男的行程,安排大致相同,只是我们的行程没有规定目标,走到哪算哪吧。

长江第一湾到了。车停在路旁,很多当地人在路旁的一个平台上摆了小摊,于是下车拍照。买了一串香蕉,当作早餐和Young分了。肚子总算舒服了点,不用靠健胃消食片补充营养了。看到了熟悉的长江,有些激动。可第一湾没有想象中的宏伟,也许是角度的问题吧。


长江第一湾

2个钟头后,车到了桥头,司机说,如果做当地人的小车进景区,只用20¥买门票,可以省下10¥。我们要求进去后再付钱,谈妥后成交,于是换车。进入景区时却没人要求买门票,下车时要了张,留做纪念吧。

1000多的太阳已经有些晒人了,摸上油,米国人却已早早的走在了前头。跟了上去,出门在外,多结个伴总不是坏事。几个当地人(向导)牵着马匹紧紧跟随。想到曾经读过的游记,几个美眉还走到了虎跳峡,于是没做请向导的打算。只是其中一个向导仍然跟着,走在后面,锲而不舍的样子。也好,有个当地人跟着,至少我们不会迷路。路上,Young和米国人聊上了,这才知道,米国人也是搞计算机的,做数据库。晕,原来今天这车都是CS的。米国人很健谈,他辞了工作,一个人外出旅游快1年了,中国只是其中一站。


去纳西雅阁路上见到的雪山,金沙江

沿路都有标记,自己徒步不用担心迷路

一路同行,太阳越发晒人,沿路也都有些标记,指引我们走向徒步休息的第一站,纳西雅阁。1100刚过我们就抵达纳西雅阁。向导说我们的脚力还行,今天应该可以到Tina’s,也就是中峡客栈。纳西雅阁象普通的纳西人家,四合院,大红色,很富丽的样子。门上的雕花也各不相同,南面立着几根柱子,挂着着大片大片金黄的玉米。云南的山地居多,多种植玉米、豆类等粮食。这种红黄的搭配越显富贵古典。午饭要了一碗牛肉花饭,还有西红柿蛋汤,清抄土豆丝,老米也是一份花饭加一份汤,香港人来得晚些,也要了份花饭。看来花饭这种食物是流行了。只是最后只有我一人吃干净了,也许是因为我吃的快,没怎么收到fly的骚扰吧。


纳西雅阁一角


雪山,玉米


纳西雅阁的风景很
wonderful

午饭后休息了一下,1230出发,向28拐挺进,山路一直向上,这里海拔2000多,没走多远就气喘吁吁了。高原上的运动果然非常累人,把中国国家队里那群玩足球的拉到昆明来训练还是有些道理的。只是为啥那群银一出去就那么衰咧,跟尼泊尔一个档次似的。由于昆明和北京有时差,此时正是正午,太阳最辣的时候,不到一会儿就汗流浃背了,皮肤在阳光的照耀下对比也非常明显,一半黑一半白,一半生一半熟,只想将自己调个面来,烤得均匀点。还未到最艰难的28拐,我们就晕了,背上的10几斤行李成为了我们最大的负担。向导还是跟着我们,让我们把行李放到他的马匹上,10¥每人。看到老米在前面背着个小包,很爽的样子,我们只有妥协。于是轻装上阵,28拐,过了这段就成功。这段路比较陡,路的外测可以看到金沙江从两山之间穿过。也可以听到江水冲击虎跳石发出的怒吼。向导边走边数着1道拐,2道拐……也有些喘不过气来。我们已经非常疲劳,午饭太饱,还未消化就踏上这段路并不是明智的选择。思维有些空白,时间似乎过得也很快,中间休息了34次,就上到最高处,这里有个妇人摆了个摊,买些水、饮料、玉米之类的东西,还有一块突出的石头被木头围了起来,入口处写着照相8¥。妇人说,今天看照相的大老板不在,给我们打个对折,4¥就可以进去了。老米了解后很不爽的样子。虎跳石发出的巨大响声在山谷之间回荡,强烈的刺激我。“恩,我进去给上虎跳照个像就出来”,Young同意了,于是我和向导进入这段照相最好的地段,远处的山谷,脚下的上虎跳,都清晰可见,巨大的山风也似乎让我们站立不稳。不一会儿,Young和老米也跳着进来了。原来老米向那妇人买了瓶水,就进来了,俺们两个中国银还没这个老外了解中国文化了。


从哈巴上看上虎跳

上到28拐了,金沙江一路陪伴我们

收费照相点拍到的玉龙,人物被cut掉了

老米一边拍着,一边不停的喊着amazingwonderful,记住这两词了,跟老外吹牛,这两词必备。拍照结束,我们从新上路,向导介绍了一下前面的情况,也离我们而去。前面的路比较平坦,还有路标,虽然较远,但并不难走。山路也从边上逐渐拐向山中间,没有旁边的峭壁,虽然安全了许多,却也没有了先前开阔的视野,风景也从壮丽变得秀美起来。路过一个小村,一个累了的驴友躺在柴堆里休息,这时是一天中最热的时段,可我们没有时间休息,只能赶路。沿路见到的驴友并不多,只有几个反方向的外国人。这段虎跳峡徒步路线在老外中的知名度可想而知。路上还见到了一些山羊,这些山羊并不怕人,任我们拍照,有的还向我们冲过来,令我们惊慌逃窜。路上常有些山泉淌下来,很清澈,像凤凰的那次,于是撅起一些,尝了尝,有些甜、很凉。还有些橘黄色小果,老米摘了些,说不错,于是一人一点,吃了起来,酸酸甜甜的,像熟透了的西红柿。


路上的山羊,不要以为旁边没人他们就是野的,其实当地人放羊都没人管的,天黑了他们自己会回家

一路上我们行得很快,下午400多就到了Half Way,也就是中途客栈。老米的行程也就结束了,明天他会原路返回。大家坐下来休息了一下,补充了一些水。玉龙雪山就立在眼前,山风仍是猛烈的刮着,虽然干燥,仍然凉爽。远处的一些小房变成小拇指大小,于是目测了一下玉龙雪山离江面的高度,大概2000多米的样子,这里的海拔2000多,玉龙雪山最高峰4900吧,实践与理论值相差不大,这对于我们工科生来说都是件值得讨论的事。向客栈里的小姑娘打听了一下到Tina’s的行程,她说1.5个钟头可以到达。于是我们尽量享受了一下这里的美景,才和老米交换了mail500启程,向Tina’s挺进。


Half Way
室内的招牌

出了小村,仍然是一段山路,时间仍然充裕,我们放慢了脚步,一路上走走停停,路过了好几个瀑布,山泉仍然是冰凉,另我们玩兴大起。山路逐渐向外,靠向悬崖,金山江重新回到我们的脚下。在一块突出的石头上,我们停了下来。Young要在这里照相。他站了上去,为了表现他的光辉形象,我蹲下给他拍了一张,背光,人物很黑,不过很高大威猛的样子,像是登上了珠峰。于是我也站了上去,他寻找角度,让我更换姿势。“把右脚往前放点”Young说。晕,这块石头本就不大,还是歪歪的立着,山风猛烈依然。往前一步就可以滚下悬崖,掉入江中,那就真可以到长江中下游打捞我了。“不行,腿软了”,我慢慢趴了下来,“休息一下再来”,惹得我俩一阵大笑。好不容易我拍完,他又要来。这次摆pose的结果,让我们达成了共识,“人物照我们要拍到满意再走”。每个人都折腾了34次,我们才重新向前。

 
云南一个多月没下雨了,这里的瀑布小了很多


这张被列为此次虎跳峡徒步的招牌照了

这样走走停停,到了快700了仍然没见任何村庄的影子,天有些暗了,这不免另我们有些担心。于是加快了步伐,行至700,仍然没有,太阳已经歪歪斜斜的,快只能照到玉龙雪山顶了,“太阳如果下山那就黑得快了”,于是又加快了步伐。这是一段下山路,在丛林中穿行,路上都是土,对于我的这双平底鞋来说是恶梦。山里的蚊子也出来活动了,一路跟着我们,在耳边嗡嗡直唤。她们也很久没吃东西了,有这样的行为可以理解。穿过丛林,视野开阔了很多,路也变得越发复杂,出现了不少岔道,没有路标。我们只能凭着感觉,选择宽一些、不太难走的路,顺势下山。直到快800才见到一排房子,墙上隐隐约约写着几个字母。直到近了才确定是Tina’s,终于到达目的地了。于是一天的疲劳就在这一刻得到了舒解。

吃完饭,一个当地人听闻我们明天要去中虎跳,就告诉我们“那里还比较危险,每年都有人下去了没上来,今天早上八点刚下去一个,现在还没回来哪。”另我们一惊,又说“我可以带你们下去,你们下去一去一回要20¥的过路费,我只收你们10¥的导游费,一共30¥”,看我们有些犹豫,又说“你们如果要去,明早八点在这里等着就行”。一副坦然得要死的样子,令我们更加担心。“行吧,就是10¥,为了小命,明天早起跟他下去”。

然后定了住房,20¥一个床位。房里非常简陋,只有一张桌子,两张床。夜里,搬个凳子,提上瓶啤酒,在客栈的院子里坐了下来,聊聊虎跳峡、丽江、火车上,还有在凤凰的经历,恍然间不知这些到底是真是假。漫天的星星点缀着夜空,另我们更有身处另一个世界的幻想。

posted @ 2005-06-11 15:01 shimmer.rkfang 阅读(204) | 评论 (0)编辑

2005年3月1日 #

一个图形爱好者的书架.-也来介绍一下我的藏书. http://blog.csdn.net/nhsoft/archive/2004/06/23/22992.aspx

一个图形爱好者的书架.-也来介绍一下我的藏书.

早几天看到有人把自己在大学四年的书列了出来.招来一顿怀疑.我是开发图形程序的.我现在也把我的书列出来.不怕大家怀疑吧.希望能有点启示作用.

绿色的是我看完了的。红色的是没怎么看的。黄色的是看了一半以上的。

首先是基础部分:
语言类:
C++ Programming Language (Special Edition).C++的圣经级别的书.我只看原文的。不看翻译的.对球教授的翻译表示一定的保留意见.
Effictive/More Effictive C++.工程实践的最佳经验书籍.
Inside C++ Object Model .好书.看完了。你对C++的理解会变的很深刻的。
设计模式 .好书.买了看就是了。别问我为什么啊。 
More Excpetion C++ 和Effective C++有同工之处.
STL 源代码破析。正在看的过程中。不过最近最Loki Boost的兴趣大点。
STL 中文版      一本参考手册。
Moden C++ Design 看完了这本书。我估计会吐血。但是还是要看。经典啊,书的例子Loki的代码
C++自学通,我入门的书 。不过现在已经找不到了。
潭浩强的C程序设计。经典。C教材里这本最好。不许大家B4他。
C++Template : 有人说翻译的不好。我觉得还可以.

Python 语言入门。我拿来做游戏脚本用的。
Unix Shell编程

算法和基础类。
程序设计实践   给你一个很好的经验.很薄的,去买来看看。
C++分形程序设计。当年给一个JJ做毕业设计。花了半个月看完的。
数据结构(C++语言描述)影印版。好书,但是没看完。教材来着的。
数据结构(用面向对象方法与C++描述)。清华出的。看完了。
人工智能 Nilson的书。看不懂。呵呵。

开发工具和平台的书
Unix 环境高级编程 : 学Unix编程.就从这里开始吧.现在在看X-Window编程.可惜没有介绍XLib的书.因为要用OpenGL.最好还是从XLib开始.痛苦.只能看Xlib.pdf
Unix 高级编程      : 我真不相信我能检到这么一本好书.想买.但是没钱.呵呵。检一本.不错.
VC++技术内幕,翻译的好烂啊。不过当时我不知道。最后还是看完了。
Windows下的C语言编程。我的 Win32入门书籍。
Win32程序员指南,我的Win32提高书籍。10块一本。呵呵。
Windows 核心编程。看完了这个。大家说我是个高手了。
深入浅出MFC.   看了一半后,我自己去看MFC的代码了.
ATL 开发人员指南  没怎么看.很实用的样子.
COM 本质论 .看完了大长见识,我就是看了他后,才知道接口的概念的.
ATL 本质论 ,看了后让我模板水平有不少提高.
Linux内核编程 没什么好说的
X86的体系结构和汇编
忘记了具体名字了。大概 是这个名字.我的汇编知识都是从这里来的。只看了前面的部分
汇编语言程序设: 钱晓捷主编.有介绍SSE和MMX的。很不错哦。 也很便宜
应用程序调试技巧: 很经典的调试书.Numega公司的工程师写的.(出品SoftICE的那个公司).有些技巧只能用神奇来形容.

专业的图形书
图形开发人员指南 著名的黑皮书.我是怀着崇拜的心情收藏这本书的。John Carmack做的序.Micheal Abrash的书.偶像啊。
计算机图形学 (清华大学)。烂书。不过也差不多看完了。现在在一个 MM手里。
图形学(电子工业出版社)老外的书。不错。正在看。
计算机图形学算法基础:经典。没看完。看了1/3了。翻了一遍。
计算机真实感图形的算法基础。国内最好的图形学的书。刚拿到。正在看。
非真实感计算机图形学: 刚买到的.不是太有用。太学术了。
游戏编程精粹 1/2/3. 中文版。偶尔翻一两篇不错的。不过我要对着英文的看才看的懂。
OpenGL Red Book .中文版还可以.非读不可.
OpenGL 超级宝典 比较好.很实用,对初学者很好.
3D Games Vol1 . 就是介绍Fly 3D 的书。看了一半了。很不错。
Real-Time Rendering 1. 正在看。很好的书
Real-Time Rendering 2: 中文版和英文版都有:
CG 教程:  推荐你学好图形学后再来看.
OpenGL Shading Languge : 看了前面的大半了。
GPU Gems :                    刚买到的.花了我350大元.不过好看.
3D Math Primer For Computer Graphics and 3D Games. 数学书里就这本好一点了。
3D Game Engine Design  正在看。对着书写自己的物理引擎。
ShaderX 2 Tricks .   没看。刚拿到。经典到不用介绍的程度了。
还有其他打印的资料无数 :-)


其他的看似没有用,其实最有用的书.
微积分: 高等教育出版社.
数学分析:上下册.
理论力学: 上下册
傅立叶变换与小波分析: 没看明白
大学物理: 1-3 册.
空气动力学: 我的老本行.(偶学航空发动机滴)

/**************************

For Games & for Dreams
Stanly lee  xheartblue

HP: http://gamehunter.3322.net/xpertsoft/

?*************************/

posted @ 2005-03-01 11:04 shimmer.rkfang 阅读(3399) | 评论 (2)编辑

2005年2月28日 #

/////////////////////转贴/////////////////////

C++语言的运行时环境是基于栈的环境,堆栈跟踪(trace stack)就是程序运行时能够跟踪并打印所调用的函数、变量及返回地址等,C++异常中的堆栈跟踪就是当程序抛出异常时,能够把导致抛出异常的语句所在的文件名和行号打印出来,以及把调用抛出异常的语句的函数以及其它上层函数信息都打印出来。
1. 为什么需要堆栈跟踪
当你在开发程序时,你是否曾遇到过程序运行过程中突然当机,而你不知道哪一行代码出的问题;你是否曾遇到过程序调试过程中突然抛出异常,而你不知道哪一行代码出的问题;你是否曾遇到过当你在单步调试时突然抛出异常而你却忘了单步执行到哪一步时抛出的异常,于是你只好重来一次。Beta程序在客户那里试运行当中,突然当机,而你不能调试,只能依据客户报告的一些信息来找bug,而客户大多不熟悉程序开发,所以他们报告的信息太少使你感觉无从下手、一筹莫展。
如果你碰到过以上情况,你就只好痛苦地一条一条单步执行语句,看抛出异常的语句在哪,检查非法访问内存的语句在哪里,糟糕的是根据海森堡不确定原理,有时当你调试时又不出问题了。所以幸运的话,你能很快就找到bug,不幸的话,几小时或几天都不能找出问题所在,并将成为你的梦魇。我在程序开发过程中,就经常碰到以上这些情况。
众所周知,在程序开发中发现一个bug将比改正这个bug难度大很多。所以如果有一个方法能够在程序出错时把出错信息打印出来,这样将大大方便找到bug,加快程序开发速度,提高程序的质量。这样,当客户报告程序出错时,你只需要客户把日志发送给你,你根据这个日志里的异常堆栈信息就能轻松发现问题所在。
在java中就有堆栈跟踪功能,它能在程序抛出异常时,能够打印出能够把导致抛出异常的语句所在的文件名和行号,C#中也有这个功能。很多人认为用java开发程序比用C++开发程序要快,我认为java有抛出异常时能够跟踪堆栈这个功能是其中的一个重要原因。

2. 如何实现C++异常中的堆栈跟踪
要实现堆栈跟踪,必须依赖于底层机制即操作系统或虚拟平台,java与jvm虚拟平台绑定,C#与.NET虚拟平台绑定,它们都提供了堆栈跟踪的功能,而C++与操作系统或平台无关,所以没有提供这个功能,但是否能够利用操作系统的系统函数实现这个功能呢?下面简要介绍如何在Windows2000下实现C++异常中的堆栈跟踪。
在Windows中,C++异常底层的实现是通过Windows中的结构化异常SEH来实现的,结构化异常包括如除0溢出、非法内存访问、堆栈溢出等,虽然用catch( … )能够捕获结构化异常,但不能知道是哪种结构化异常,所以第一步就是要把结构化异常转化为C++异常,Windows中的_set_se_translator()函数可以实现这个功能。先建立一个转化函数:void _cdecl TranslateSEHtoCE( UINT code, PEXCEPTION_POINTERS pep ) ;在这个转化函数中抛出一个继承C++标准异常的类,如CRecoverableSEHException(可以恢复的结构化异常类)和CUnRecoverableSEHException(不可以恢复的结构化异常类),这两个类继承CSEHException,CSEHException继承标准C++异常的基类exception。然后在main函数开始处调用 _set_se_translator(TranslateSEHtoCE ),这样就可以把结构化异常转换为C++异常。
另外,由于VC中默认new失败时并不抛出异常,所以需要让new失败时抛出异常,这样可以统一处理,可以使用WINDOWS中的_set_new_handler( )转化,让new失败时抛出异常。同上,先建立一个转化函数 int NewHandler( size_t size ),在这个转化函数中抛出C++标准异常的类bad_alloc,在main函数开始处调用 _set_new_handler (NewHandler)。
接着在CSEHException的构造函数中跟踪堆栈,把导致抛出结构化异常的语句所在的文件名和行号打印出来,调用void ShowStack( HANDLE hThread, CONTEXT& c )。ShowStack函数封装了跟踪堆栈所需调用的各种系统API。它的功能就是根据参数c(线程的上下文),得到当前程序的路径,枚举所调用的系统动态连接库,然后按照从里到外的顺序打印出所有执行的函数名及其所在的文件名和行号。
创建自己的异常类使其具有堆栈跟踪的功能,定义自己使用的异常基类如CMyException(当然,如果你愿意,你可以修改其命名),令其继承标准C++异常类domain_error(当然也可以继承exception),然后在CMyException的构造函数中调用void ShowStack( HANDLE hThread, CONTEXT& c ),这样就可以实现堆栈跟踪,其它自定义的异常继承CMyException,就自动获得堆栈跟踪的功能。这样就形成了一个完整的类层次。

exception

logic_error runtime_error?
length_error
out_of_range bad_alloc bad_cast range_error
invalid_argument bad_exception overflow_error
domain_error ios_base:failure underflow_error

CMyException(自定义异常基类) CSEHException(结构化异常基类)?

CRecoverableSEHException CUnRecoverableSEHException

CSocketException(与socket相关的异常)?
CConfigException(与配置文件相关的异常)
注:CMyException上面的异常类均为标准C++的异常类。
注:以上异常类的基类均为exception。


本人实现的具有堆栈跟踪的C++异常类库和测试程序可以从www.smiling.com.cn中的umlchina小组中下载StackTraceInC.zip文件。
3. 如何使用C++异常中的堆栈跟踪类库
下载的文件包括Exception.h Exception.cpp(具有堆栈跟踪功能的异常类库), main.cpp, Test1.h, Test1.cpp (测试代码)。
让我们先感受一下堆栈跟踪的威力,运行下载的示例程序,将打印出如下结果(因为输出太长,所以只节选了其中一部分)。主程序为:
void main(){

// 在每个线程函数的入口加上以下语句。
// 检查内存泄露。
CWinUtil::vCheckMemoryLeak();
// 使new函数失败时抛出异常。
CWinUtil::vSetThrowNewException();?
// 把WINDOWS中的结构化异常转化为C++异常。
CWinUtil::vMapSEHtoCE();
// 初始化。
CWinUtil::vInitStackEnviroment();
try {
// 捕获非法访问内存的结构化异常。
int* pInt; // 故意不分配内存
*pInt = 5; // 应该显示出这一行出错。
}
// 捕获可恢复的结构化异常。
catch ( const CRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
// 捕获不可恢复的结构化异常。
catch ( const CUnRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
// 捕获标准C++异常。
catch ( const exception& e ) {
cout << e.what() << endl;
}
// 捕获其它不是继承exception的异常。
catch ( ... ) {
cout << " else exception." << endl;
}
try {
// 捕获自定义的异常。
throw CMyException( " my exception" ); // 应该显示出这一行出错。
}
catch ( const CRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const CUnRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const exception& e ) {
cout << e.what() << endl;
}
catch ( ... ) {
cout << " else exception." << endl;
}
try {
// 捕获函数中的异常。
vDivideByZero(); // 应该显示出这个函数抛出的异常。
int i = 1;
}
catch ( const CRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const CUnRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const exception& e ) {
cout << e.what() << endl;
}
catch ( ... ) {
cout << " else exception." << endl;
}
try {
// 捕获另一源文件Test1.cpp中的函数抛出的异常。
vTestVectorThrow();// 应该显示出在这个函数抛出的异常。
int i = 1;
}
catch ( const CRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const CUnRecoverableSEHException &bug ) {
cout << bug.what() << endl;
}
catch ( const exception& e ) {
cout << e.what() << endl;
}
catch ( ... ) {
cout << "else exception." << endl;
}
int i;
cin >> i; // 防止无意中按键使程序退出。
}
对于第1个异常输出为:
0 .V 004066d5 0040779f 0012ff70 00000000 _main + 85 bytes
Sig: _main
Decl: _main
Line: H:\C++ Test\StackWalk\Test\main.cpp(50) + 3 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe
从上面第4行可以知道在main.cpp文件的第50行抛出的异常,找到这一行就是*pInt = 5;然后检查上下文,哦,没有分配内存,于是“臭名昭著”的非法内存访问就轻易发现了!Is it powerful?
对于第2个异常输出为:
1 .V 0040683d 0040779f 0012ff70 00000000 _main + 445 bytes
Sig: _main
Decl: _main
Line: H:\C++ Test\StackWalk\Test\main.cpp(72) + 49 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe
从上面第4行可以知道在main.cpp文件的第72行抛出的异常,找到这一行就是throw CMyException( " my exception" ); 哦,是自定义异常。
对于第3个异常输出为:
0 .V 004065f5 0040697c 0012fe98 00000000 void __cdecl vDivideByZero(void) + 37 b
ytes
Sig: ?vDivideByZero@@YAXXZ
Decl: void __cdecl vDivideByZero(void)
Line: H:\C++ Test\StackWalk\Test\main.cpp(26) + 6 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe

1 .V 0040697c 0040779f 0012ff70 00000000 _main + 764 bytes
Sig: _main
Decl: _main
Line: H:\C++ Test\StackWalk\Test\main.cpp(100) + 0 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe
从上面第5行可以知道在main.cpp文件的第26行抛出的异常,找到这一行就是int iRet = 5 / iZero; 哦,是除零异常。然后从上面第12行可以知道调用这个函数是在main.cpp文件的第100行,就是vDivideByZero();的下一行(注意因为vDivideByZero();函数已经调用了,所以显示的行数都是它的下一行)。这样,我们就可以知道一个异常发生的完整过程。
对于第4个异常输出为:
0 .V 004070ca 00406ab9 0012fe98 00000000 void __cdecl vTestVectorThrow(void) + 7
4 bytes
Sig: ?vTestVectorThrow@@YAXXZ
Decl: void __cdecl vTestVectorThrow(void)
Line: h:\c++ test\stackwalk\test\test1.cpp(13) + 10 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe

1 .V 00406ab9 0040779f 0012ff70 00000000 _main + 1081 bytes
Sig: _main
Decl: _main
Line: H:\C++ Test\StackWalk\Test\main.cpp(118) + 0 bytes
Mod: Test[H:\C++ Test\StackWalk\Test\Debug\Test.exe], base: 0x00400000h
Sym: type: PDB, file: H:\C++ Test\StackWalk\Test\Debug\Test.exe
从上面第5行可以知道在test1.cpp文件的第13行抛出的异常,找到这一行就是 vectInt[ 3 ] = 100; 检查上下文,发现没有给vectInt分配空间。然后从上面第12行可以知道调用这个函数是在main.cpp文件的第118行,就是vTestVectorThrow();的下一行。
那么如何使用这个类库呢?对于新工程,首先把exception.h和exception.cpp加入工程,你需要把自定义的异常类继承自CMyException,这样自定义的异常类就具有堆栈跟踪功能,其次在每个线程的入口函数加上以下几个函数调用(注意:必须在每个线程的入口都要调用,当然如CWinUtil::vInitStackEnviroment();不需要,只需要在main入口即可,但如果在每个线程的入口都要调用也不会有副作用):
` // 在每个线程函数的入口加上以下语句。
// 检查内存泄露。
CWinUtil::vCheckMemoryLeak();
// 使new函数失败时抛出异常。
CWinUtil::vSetThrowNewException();?
// 把WINDOWS中的结构化异常转化为C++异常。
CWinUtil::vMapSEHtoCE();
// 初始化。
CWinUtil::vInitStackEnviroment();
然后如下所示捕获异常:
try {
vTest();// 假设要捕获vTest()函数可能抛出的异常。
}
catch ( const CRecoverableSEHException &bug ) {// 用于捕获可恢复的结构化异常。
cout << bug.what() << endl;
}
catch ( const CUnRecoverableSEHException &bug ) {// 用于捕获不可恢复的结构化异常。
cout << bug.what() << endl;
}
catch ( const exception& e ) {// 用于捕获标准C++异常及其子类。
cout << e.what() << endl;
}
catch ( ... ) { // 用于捕获那些抛出非结构化异常和不是继承exception的异常。
cout << " else exception." << endl;
}
当然你对于结构化异常没有其它特别的处理策略,也可以简化为:
try {
vTest();// 假设要捕获vTest()函数可能抛出的异常。
}
// 用于捕获标准C++异常及其子类。因为结构化异常继承自exception,所以这里也能捕获// 结构化异常。
catch ( const exception& bug ) {
cout << bug.what() << endl;
}

对于已有的工程,首先把exception.h和exception.cpp加入工程,把原来的自定义的异常类继承自CMyException,然后同上的方法捕获异常,每个线程入口增加初始化函数即可,可以与你原来的异常处理完美集成。
对于在MFC中的用法,可以按如下方式捕获异常:
try {
vTest();
}
catch ( const exception& e ) {
cout << e.what() << endl;
}?
// CException是MFC中异常基类,MFC中的异常通常从堆中分配,所以应通过指针捕获,// 而且使用完之后还应该调用delete函数清除内存。
catch ( CException* e ) {
// hadle exception
e->delete();?
}
即在MFC异常上加一层捕获标准C++异常和结构化异常以及自定义异常。另外由于MFC中已经自动有了处理内存泄露的机制,所以需要删除exception.h文件的第34行到第40行(有关内存泄露的说明见下面),由于在MFC中每个.cpp文件开始处都要包含stdafx.h,所以还需要在exception.cpp文件开始处加上#include “stdafx.h”,不然会编译不通过。
如果你希望把堆栈信息输出在文件中,以防丢失,可以使用IO重定向功能(有关IO重定向可参考Jim Hyslop and Herb Sutter的文http://www.cuj.com/experts/1903/hyslop.htm ),即在main()函数开头加入以下语句:
ofstream ofLog( "exception.txt", ios_base::app );
streambuf *outbuf = cout.rdbuf( ofLog.rdbuf() );
这样,所有输出到console的信息就重定向到exception.txt文件中了。如果你想恢复,则可以加入以下语句:
// restore the buffers
cout.rdbuf( outbuf );
对于release版本,如果你运行,你会发现程序不能捕获非法内存访问、除零等结构化异常,这是因为VC在release版默认是同步异常,不捕获结构化异常,只能捕获C++的异常,所以你需要修改编译选项,采用异步异常模型,在project->setting->c/c++->project options框中增加/EHa的编译选项。另外,release版默认不生成调试符号文件,这样你就不能不能打印出抛出异常的代码的行号等信息,所以你需要修改编译配置,方法如下:Project->Settings->c/c++页中的debug info列表选项中选择program database项。这样release版本也能实现堆栈跟踪。当然,这样会使release版本减慢速度,而且还要带一个debug info文件,因为有些bug只有在release版本中才会出现,而且release版是真正给客户使用的,所以必须测试release版,可以考虑release的beta1和beta2版本带这些调试信息,这样的话,因为debug版和release版都测试通过,发行给客户的最终正式版可以通过设置一个宏注释掉这些调试信息,恢复成同步异常模型,即恢复成VC默认的release版配置。
4. 其他需要注意的问题
本类库还有检查内存泄露的功能,只要你在每个.cpp文件的所有#include之后,加上以下语句:
// 以下几行是能够定义到发生内存泄露的代码行。在每个.cpp文件都应该声明。
#include “Exception.h”
#ifdef _DEBUG?
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
然后以debug方式启动程序,当程序正常退出或关闭时(注意不能用stop debug的命令停止,否则将不会打印出内存泄露的信息),在VC的debug窗口将会打印出有可能产生内存泄露的源代码信息,包括文件名和行号。由于MFC程序自动会生成这些代码,所以在MFC程序中不需要手工添加这些代码。例如,当你以debug方式运行下载的测试程序,当程序正常退出后,在debug窗口会显示如下语句:
Detected memory leaks!
Dumping objects ->
H:\C++ Test\StackWalk\Test\main.cpp(88) : {184} normal block at 0x00632D50, 100 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD?
Object dump complete.
从上面第3行可以知道在main.cpp文件的第88行产生了内存泄露,找到这一行就是 char* pcLeak = new char[ 100 ]; 检查上下文,发现果然没有释放内存。
当然如同你使用Purify、BoundsChecker等工具检查内存泄露一样,它也会谎报军情,有些不会内存泄露的地方,它也告诉你内存泄露了,尤其当你使用了大量STL类库时,这就需要你细心检查上下文,以确定是否是内存泄露了。
本类库由于使用了一些VC中特有调试符号特性,所以可能不能在其它编译器下通过。另外,本文讨论的堆栈跟踪实现都是基于Windows 2000以上,Win98和Win95将不能输出导致抛出异常的语句所在的文件名和行号。本类库也不能在Unix或Linux下运行。有在Unix或Linux平台工作的读者朋友如果有兴趣,可以实现一个在Unix或Linux平台运行的C++异常堆栈跟踪类库。
本类库不能跟踪标准C++异常及其它你不能控制的异常的堆栈信息,即当这些异常抛出时,不能输出抛出异常语句的文件名和行号信息。这是因为标准C++异常是语言内置的,而其它类库的异常你不能控制其构造函数。这是一个小小的遗憾,不过你可以通过异常说明知道它是哪一种异常,可能在程序的哪一些C++函数中抛出,这样你也能很快地找到错误之处。
有了完善的异常类层次,你可以在程序中干任何事,异常过滤机制和堆栈跟踪会忠实的记录任何错误,除了你在析构函数抛出异常以及重复删除不为NULL的指针,这两种情况下程序还是会当掉,而且不能记录堆栈信息。当然,对于缓冲区溢出、堆写越界等情况,本类库还是无能为力,不过,你可以借助Purify、BoundsChecker等工具来检查程序运行中是否有这类问题。
5. 小结
谁说C++就不能有堆栈跟踪的功能。有了这个具有堆栈跟踪功能的异常类库,你将如虎添翼,必将加快你开发程序的进程。
Enjoy!

参考资料:
1. Everett N.McKay Mike Woodring.《WINDOWS程序调试》译者:何健辉等 中国电力出版社
2. Jeffrey Richter. 《WINDOWS核心编程》译者:王建华等 机械工业出版社
3. Bjarne Stroustrup. 《The C++ Programming Language, Special Edition》高教出版社
4. Jim Hyslop and Herb Sutter 《Redirections》http://www.cuj.com/experts/1903/hyslop.htm
posted @ 2005-02-28 21:46 shimmer.rkfang 阅读(624) | 评论 (1)编辑

2005年1月5日 #

发信人: fist (星仔迷), 信区: SysInternals WWW-POST
标  题: Kernel Dll的范例(1)
发信站: 武汉白云黄鹤站 (Mon Jul  2 15:11:09 2001) , 转信
 
目录
    1。建立文件
    2。编译
    3。启动和测试
    4。问题与解决方法
 
 
内容:
--------------------------------------------------------------------------------
  1。建立文件
   工程目录结构
      Slave存放内核Dll的源文件,Master存放了调用内核Dll的驱动程序,App是一个应用层
测试程序, Include存放的是一个公共头文件MyIoCtl.h.
      KernelDll
         |
         |---------Include-----MyIoCtl.h
         |
         |---------Slave-------Slave.c SOURCES Makefile,slave.Def
         |
         |---------Master------Master.c SOURCES Makefile
         |
         |--------App---------test.c
 
-------------------------------------------------------------------------------
Include\myIoCtl.h
 
   //MyIoctl.h
 
   //CTL_CODE macro defined in devioctl.h in DDK\inc.
   //custom device types (non Microsoft) in range 32768 to 65535
   //custom user defined function codes in range 2048 to 4095
   #define FILE_DEVICE_FOO 65534
   #define IOCTL_CALL_KERNEL_MODE_DLL CTL_CODE(FILE_DEVICE_FOO, 2049,
     METHOD_BUFFERED, FILE_ANY_ACCESS)
 
-------------------------------------------------------------------------------
    Kernel Dll部分
 
    [1]Slave.c
      #include "ntddk.h"
      #include "MYIOCTL.H"
 
      NTSTATUS
      DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING
         RegistryPath ){
      return STATUS_SUCCESS;
      }
 
      NTSTATUS
      _declspec( dllexport )DoSomethingMeaningless(IN PIRP pIrp,
           IN PIO_STACK_LOCATION  pIrpStack){
      USHORT *pw;
      /* check to see if this is our ioctl. */
      if (pIrpStack->Parameters.DeviceIoControl.IoControlCode !=
       IOCTL_CALL_KERNEL_MODE_DLL)
           return STATUS_INVALID_PARAMETER;
 
      /* check to see if output buffer size is big enough. */
      if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
        (USHORT)) {
         pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
         pIrp->IoStatus.Information = 0;
         return STATUS_BUFFER_TOO_SMALL;
       }
 
      /* return a value back to the user. */
      pIrp->IoStatus.Information = sizeof( USHORT );
      pw = (USHORT *)pIrp->AssociatedIrp.SystemBuffer;
      *pw = 0XAA55;
      pIrp->IoStatus.Status = STATUS_SUCCESS;
      return STATUS_SUCCESS;
      }
 
    [2]SOURCES
    # SOURCES FILE FOR SLAVE.SYS
    TARGETNAME=SLAVE
    TARGETPATH=obj
    TARGETTYPE=EXPORT_DRIVER
    INCLUDES=$(BASEDIR)\inc;..\Include
    SOURCES=SLAVE.C
    C_DEFINES=-DUNICODE -DSTRICT
 
 
   [3]Makefile
    #
    # DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
    # file to this component.  This file merely indirects to the real make file
    # that is shared by all the components of NT OS/2
    #
    !INCLUDE $(NTMAKEENV)\makefile.def
 
   [4]Slave.def-----不知道为什么这一次它非要我写Def文件。:(.
     ;DEF FILE FOR SLAVE.SYS
      NAME SLAVE.SYS
      DESCRIPTION 'SLAVE.SYS'
      EXPORTS
 
 
-------------------------------------------------------------------------------
   调用Dll的驱动程序
 
   [1]Master.c
   #include "ntddk.h"
   #include "myioctl.h"
 
typedef struct _FOO_DEVICE_EXTENSION {
   ULONG Information;
} FOO_DEVICE_EXTENSION, *PFOO_DEVICE_EXTENSION;
 
 
// Function declarations
NTSTATUS
MasterDispatchIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
 
NTSTATUS
_declspec( dllimport )DoSomethingMeaningless(IN PIRP pIrp, IN PIO_STACK_LOCATIO
 pIrpStack );
 
NTSTATUS
DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
 )
{
        UNICODE_STRING nameString, linkString;
        PDEVICE_OBJECT deviceObject;
        NTSTATUS status;
 
        //slave.sys needs to start before master.sys
        // Create the device object.
        RtlInitUnicodeString( &nameString, L"\\Device\\MASTER");
        status = IoCreateDevice( DriverObject,
                sizeof(FOO_DEVICE_EXTENSION),
                 &nameString,
                FILE_DEVICE_UNKNOWN,
                0,
                FALSE,
                &deviceObject );
 
        if (!NT_SUCCESS( status ))
                return status;
 
        // Create the symbolic link.
        RtlInitUnicodeString( &linkString, L"\\DosDevices\\MASTER");
        status = IoCreateSymbolicLink (&linkString, &nameString);
        if (!NT_SUCCESS( status )) {
           IoDeleteDevice (DriverObject->DeviceObject);
           return status;
        }
 
        // Initialize the driver object with this device driver's entry points.
        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MasterDispatchIoct
;
 
        return STATUS_SUCCESS;
}
 
NTSTATUS
MasterDispatchIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
        NTSTATUS                                  status;
        PIO_STACK_LOCATION          irpSp;
 
        // Init to default settings- we only expect 1 type of
        // IOCTL to roll through here, all others an error.
        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;
 
 
        // Get a pointer to the current location in the Irp. This is where
        // the function codes and parameters are located.
        irpSp = IoGetCurrentIrpStackLocation( Irp );
        switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
                case IOCTL_CALL_KERNEL_MODE_DLL:
                        if ( NT_SUCCESS( DoSomethingMeaningless( Irp , irpSp) )
) {
                                status = STATUS_SUCCESS;
                        }
                        else
                                status = STATUS_INVALID_PARAMETER;
                    break;
 
                default:
                                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER
                    break;
        }
 
        // DON'T get cute and try to use the status field of
        // the irp in the return status. That IRP IS GONE as
        // soon as you call IoCompleteRequest.
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        // We never have pending operation so always return the status code.
 
        return status;
}
    [2]SOURCES
     # SOURCES FILE FOR MASTER.SYS
     TARGETNAME=MASTER
     TARGETPATH=obj
     TARGETTYPE=DRIVER
     TARGETLIBS=$(BASEDIR)\lib\slave.lib
     INCLUDES=$(BASEDIR)\inc;..\Include
     SOURCES=MASTER.C
     C_DEFINES=-DUNICODE -DSTRICT
    [3]Makefile
    #
    # DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
    # file to this component.  This file merely indirects to the real make file
    # that is shared by all the components of NT OS/2
    #
    !INCLUDE $(NTMAKEENV)\makefile.def
 
 
------------------------------------------------------------------------------
   测试应用程序
   #include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "stdlib.h"
#include "myioctl.h"
int main ( void )
{
    HANDLE hDriver;
    DWORD cbReturned = 0x0;
    WORD iobuf = 0x0;
 
    // Try to open the device
    if ((hDriver = CreateFile("\\\\.\\MASTER",
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL )) != INVALID_HANDLE_VALUE )
            printf ("\nRetrieved valid handle for MASTER driver\n");
 
    else {
        printf ("Can't get a handle to MASTER driver\n");
        return 0;
    }
 
    // iobuf initialized to zero, so we better get something different after ca
l.
    if ( DeviceIoControl (hDriver,
                        (DWORD) IOCTL_CALL_KERNEL_MODE_DLL,
                        &iobuf,
                        (DWORD)(2*(sizeof (WORD))),
                        &iobuf,
                        (DWORD)(2*(sizeof (WORD))),
                        &cbReturned,
                        (LPVOID)NULL) )
    {
        if (iobuf == 0xAA55) {
                        printf("DeviceIoControl worked and returned the correct
value.\n");
        } else {
                        printf("DeviceIoControl worked but reurned the wrong va
ue %x\n", iobuf);
        }
    } else {
                    printf("DeviceIoControl Failed\n");
    }
    }
    CloseHandle(hDriver);
    return 1;
}
———————————————————————————————————————?
——
  2. 编译
   以下的编译过程是用DDK编译的。环境为W2k.
  (1)Slave
      进入目录slave,键入build -cez
   (2)Master
     (a) 进入Master,键入build -cez
        错误:don't know how to make 'e:\Ntddk\lib\slave.lib'
        原因:slave.lib 没有拷贝到制定目录。
     (b)把slave.lib拷贝到e:\Ntddk\lib\,继续编译 build -ceZ
        通过。
   (3)App--->test.exe
-------------------------------------------------------------------------------
                                                           (To be continued)
      *************************************************************************
                    printf("DeviceIoControl Failed\n");
    }

发信人: fist (星仔迷), 信区: SysInternals WWW-POST
标  题: Kernel Dll的范例(2)
发信站: 武汉白云黄鹤站 (Mon Jul  2 20:37:08 2001) , 转信
 
3.启动与测试
    (1)拷贝slave.sys和master.sys到目录e:\winnt\system32\drivers\
   (2)写注册表
        master.ini
          \registry\machine\system\currentcontrolset\services\MASTER
            Type = REG_DWORD 0x00000001
            Start = REG_DWORD 0x00000002
            Group = Extended base
            ErrorControl = REG_DWORD 0x00000001
            Tag = REG_DWORD 0x00000002
 
        slave.ini
         \registry\machine\system\currentcontrolset\services\SLAVE
            Type = REG_DWORD 0x00000001
            Start = REG_DWORD 0x00000002
            Group = Extended base
            ErrorControl = REG_DWORD 0x00000001
Tag = REG_DWORD 0x00000001
 
Regini slave.ini
Regini master.ini
   (3)重启计算机
   (4)打开并运行程序test.exe,显示
Retrieved valid handle for MASTER driver
DeviceIoControl worked and returned the correct value.
表明运行成功。
4.问题与解决方案
(1)    加载顺序。
在本例子中要求slave.sys先于master.sys启动,在很多应用中也有这样的需要。在本例子

,我们主要的技术是定义一个组”extended base”,然后相同的start,type,唯一的区别?
slave.sys的tag=2>master.sys的tag=1.
加载顺序主要决定于start,(Group)GroupOrderList, DependOnGroup,适当调整这些值就可

确定加载顺序了。
(2)    编译需要库文件支持。也就是说编译master.sys时依赖于slave.lib。其实我猜?
s.lib也是一个kernel Dll的形式提供给驱动程序开发者使用的。相类似的在system32\dri
ers下也存在ndis.sys。其他还有什么tdi也是这样的。
(3)    现在考虑一下EDIS用Kernel Dll来实现存在的问题。对于问题1,也许很好决定,
GroupOrderList可以很好地控制kernel Dll的加载顺序。对于库支持,好像久有问题了(?

敢十分确定,我的初略想法,希望各位,特别是老斑竹提出意见)。问题在于如果每增加?
个算法,都得把EDIS的算法管理模块编译一次,以支持新的算法。好像根本就不应该用DLL

思想来实现,太不灵活了。这里也许想到EDIS唯一的思路是模仿动态加载,而且是显式调?
应用层Dll ,或者更确切地说是像COM技术,提供一个特殊的接口QueryInterface.通过这?
特殊接口,算法管理模块可以得到Dll到底支持什么算法,那些使用该算法的函数等。这样

制算法的加载只需要在应用层或其他地方告诉算法管理模块需要加载或卸载那些提供算法?
sys.。然后管理模块自动加载算法sys,查询接口,并纪录接口信息。这样的好处是不需要?
加算法时重新编译算法管理模块。
当然这种方法和老斑竹的想法有点不同,这里算法管理模块一直是主动,而不是被动。这?
种方法都不是用Kernel Dll来实现,而是一般驱动程序的技巧,更准确的说是一种灵活的?
构。也是写到这里顺便瞎说的,好像与文章主体无关。
 
******************
 
--

posted @ 2005-01-05 17:02 shimmer.rkfang 阅读(611) | 评论 (0)编辑

转贴: [学术研究]计算机科学与技术学生学习基础材料参考
bigsea 发表于 2004-12-11 15:53:00

[本文在以前曾多次看过,现在转到BLOG上,供以后参考]
Newsoftstudio(翻译)

出处     http://williamstallings.com/StudentSupport.html

这份材料是我在帮美国MIT的William Stallings博士翻译站点的时候的一部分内容,感觉对国内的学生帮助会很大。写给大家,希望能对大家有所帮助。材料中涉及的所有内容版权归原作者所有,收集信息的版权归William Stallings博士所有。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
关于一些计算数学基础性的材料

Math Refresher:(ftp://shell.shore.net/members/w/s/ws/Support/Math.pdf
这个概论覆盖了你在高中学得很多东西,你可能已经忘记了。包括一些正弦和对数函数的基本的公式,一个关于 log 变化率的讨论,以及离散概率论基础,William Stallings编写,2002年2月8日更新。

Number Systems:(ftp://shell.shore.net/members/w/s/ws/Support/NumberSystems.pdf
十进制,二进制,十六进制,包括了一个关于数制转换的讨论,William Stallings编写。

Queuing Analysis:(ftp://shell.shore.net/members/w/s/ws/Support/QueuingAnalysis.pdf
一个对计算机科学家非常重要的工具的实践指南William Stallings编写。

Theoretical Computer Science Cheat Sheet:(http://bit.csc.lsu.edu/~seiden/cheat.pdf
路易斯安纳州立大学Steven Seiden教授编写,10页的常用公式以及其他一些对计算机科学家很有用的信息,版本2.01,1999年9月编写。.

The Mathematical Atlas:(http://www.math-atlas.org/
一个关于数学方面的非常大的文章收藏。每篇文章都对本学科,应用以及相关的领域和一些选择性的话题作了基本的介绍。这里还提供了很多讨论这些问题的详细材料,提供书籍下载和在线浏览两种方式。

Topics in Mathematics:(http://archives.math.utk.edu/topics/index.html
网上的数学资源链接, 按照话题组织在一起,,有关键字搜索功能。这个站点同时也显示了阅读这些材料所需的数学背景知识。

Math Tables and Formulas: Tables featured include:(http://www.sosmath.com/tables/tables.html
三角恒等式 ,推论, 不定积分,定积分,二项式系数及其公式, 这里还提供了一个搜索引擎以及到其他S.O.S站点和S.O.S数学讨论板的链接。

Math Reference Tables:(http://www.math2.org/index.xml
一个极好的提供下载数学资料列表收集。

Prime Mathematics Encyclopedia:(http://www.mathacademy.com/pr/prime/index.asp
一个数学术语与概念的很丰富的收集。

*******************************************************************************
How-To


How to Solve and Write Up Homework Problems:(ftp://shell.shore.net/members/w/s/ws/Support/hw_how_to.pdf
来自巴尔的摩的马里兰州大学  Alan Sherman教授的有帮助的建议。

Advice on Writing Technical Reports:
(http://www.csee.umbc.edu/~sherman/Courses/documents/TR_how_to.html
这个也是Alan Sherman教授编写的。

Advice on Research and Writing:
(http://goanna.cs.rmit.edu.au/~jz/write/leone-how-to.html
关于如何去研究以及如何去有效的与人有效的交流的建议的收集 (主要是面对计算机科学家的)。其中包括了一些很好的链接。

Richard Felder's Student Handouts:(http://www2.ncsu.edu/unity/lockers/users/f/felder/public/Student_handouts.html
一些写给学生的有用的建议包括一些与考试相关的帖子。

How to Present a Paper in Theoretical Computer Science: (ftp://shell.shore.net/members/w/s/ws/Support/Parberry.ps.zip
北德克萨斯州大学Ian Parberry教授编写 , 美国计算机协会自动机遇科技酸性理论专业组(SIGACT)2000年3月新闻。这是一个zipped postscript格式的各种计算机科学论文的写作指南。

How to Write an Abstract:(http://www.williamstallings.com/Extras/Abstract.html
卡内基.梅隆大学Philip Koopman教授编写 。写计算机论文摘要的很好的建议。

William Strunk's The Elements of Style (1918 edition, online):
(http://www.bartleby.com/141/index.html
虽然这份材料已经写了很久了,这份短小的名作对改善你写作风格所起的作用比一些较新的要大得多。

Online Resources for Writers: (http://webster.commnet.edu/writing/writing.htm
在线写作资源的一些很好的链接的收集。

Writing Guide: (http://www.williamstallings.com/Extras/Writing_Guide.html
来自Henson学院一份很有用的总论性的论文写作指导。

Guide to Grammar and Writing:(http://cctc2.commnet.edu/grammar/
极好的一份写作与语法的彻底的讨论,包括一些指南,链接以及 FAQ。

Efficient Reading of Papers in Science and Technology:
(http://www.cse.ogi.edu/~dylan/efficientReading.html
这个小册子来自一个神秘的作者,很值得学习一下。

How To Study:(http://www.cse.buffalo.edu/~rapaport/howtostudy.html
一个提供给学生如何学习的建议的网站

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
研究资源

Networked Computer Science Technical Reference Library:
(http://www.ncstrl.org/
一个国际性的,提供给非商业性使用的用户,从很多研究会和档案室收集来的计算机科学研究报告及论文集。

Computer Science Directory: (http://citeseer.nj.nec.com/directory.html
一个组织良好的计算机科学论文与算法的搜索。

Collection of Computer Science Bibliographies:(http://liinwww.ira.uka.de/bibliography/index.html
通过很多来源组织到一起的计算机科学的科学著作参考书目,涵盖了计算机科学的大部分内容。每月更新,已经有近一百万个参考书籍。

INFOMIME:(http://infomine.ucr.edu/
一个具有大学水平的提供给老师,学生以及研究人员的虚拟图书馆Internet资源。

Links for Computer Science Researchers
(http://www.cl.cam.ac.uk/users/asa28/useful_compsci_research_links.htm
一个极好的链接收集。

#############################################################################
其他丰富的资源
Dictionary of Algorithms, Data Structures, and Problems:
(http://www.nist.gov/dads/
包括定义,问题分析,源代码样例,有些例子有动画演示。

Free Online Dictionary of Computing: (http://www.nightflight.com/foldoc/index.html
含有交叉引用的在线术语表。

Computer Related Acronyms:(http://www.geocities.com/ikind_babel/
在线缩略语表。

Acronyms and Abbreviations:(http://www.ucc.ie/cgi-bin/acronym
缩略语查找。

Association for Computer Machinery (ACM):(http://www.acm.org/membership/student/
我强烈建议每个计算机科学专业的学生都加入会员。

Institute of Electrical and Electronics Engineers (IEEE):
(http://www.ieee.org/membership/students.html
同上。

Numerical Prefixes: (ftp://shell.shore.net/members/w/s/ws/Support/Prefix.pdf
kilo, mega的两重含义及其他。

Conversion Factors:(ftp://shell.shore.net/members/w/s/ws/Support/Conversions.pdf
这个文档提供了从英国度量衡转换到公制系统(SI单元)的方法。

Conversion Web Site:(http://www.omnis.demon.co.uk/indexfrm.htm
转换器,单位和度量标准,数据表以及工具的一个收集。

Treasure Trove of Paper Summaries:(http://swig.stanford.edu/pub/summaries/
由很多计算机研究生一起编写的,这份摘要是写作的很有用的指南,同时他们提供了一个如何写作报告,论文,书的很好的向导。

What the Professor Really Means:(http://www.williamstallings.com/Extras/Prof.html

posted @ 2005-01-05 15:34 shimmer.rkfang 阅读(262) | 评论 (0)编辑

转至 http://www.china-pub.com/main/linux/linux_fengrui.htm


本期特约作者 冯锐
(会员名:phost)

  工欲善其事,必先利其器。
  掌握一门技术,兴趣是最好的老师,而书就可能是前进的导航灯。计算机图书的出版情况,从一个侧面能够反应一个国家的计算机发展水平。比如台湾,其资讯业比大陆发达的多,其计算机书籍也明显走在了大陆的前列;幸运的是最近几年大陆的计算机书籍的出版正迎头赶上。国外计算机和计算机图书的水平明显高于国内,很多出版社与国外著名的出版社合作,引进外文版的图书,例如中国电力出版社引进的Oreilly的图书,华中理工出版社引进的台湾候俊杰先生的图书,对于读者来说都是振奋人心的好消息。
  而计算机图书出版的蓬勃发展也给读者带来另外一个问题:现在的计算机图书可以用浩如烟海来形容,在书店可谓是看花了眼,其质量肯定参差不齐,而且面对不菲的价格,该如何找到自己需要的书籍,如何有效地选择自己需要的书籍呢?读者选择书籍不免会碰到以下的问题:
1. 该选择哪个出版社?
  国内计算机图书口碑比较好的几个出版社有:清华大学出版社、电子工业出版社、人民邮电出版社、机械工业出版社。清华大学出版社是老牌的计算机图书出版社,它是国内出版原著计算机图书最好的出版社,其出版的影音版的外文书籍也值得称道。机械工业出版社在我的印象中是从1997年开始大力出版计算机图书,现在已经取得了显著的成效,其属下的华章公司的网站http://www.china-pub.com是读者选择图书的一个好去处。另外还有些出版社的图书也非常不错,例如前面提到的例如中国电力出版社引进的Oreilly的图书和华中理工引进的台湾候俊杰先生的图书,都是专业内的经典之作,出版社凭借这些图书在业界内也名声大振。如果单纯论出版书籍的种类和数量,北京希望电子出版社和水利水电出版社出版可以是说是大户,但是其质量实在不敢恭维(也许是我看到的书刚好如此,但是出版社的图书就是自己的商品,质量不好牌子就倒了)。
2. 选择中文版还是英文版
  这个问题的答案很简单,如果有引进的英文版,读者的英文功底又足够的话,就不用考虑中文版了。这并非什么崇洋媚外,实在是一种无奈。计算机水平是英语语系的最高,其资料和文档大部分(大概70%)都是英文的,想在行业内立足和发展,就不可能避免英文的问题。而且国内出版的计算机图书,如果是原著,很多质量还是可以的;但是有些书籍的质量与国外著名出版社出版的图书还是有一定差距的。如果是译著,恐怕从事过相应工作的人都会明白,信、达、雅这三个字并非如此简单,真正能做到这三个字的译著恐怕凤毛麟角。而且加上引进、翻译、出版的各个环节,引进的图书恐怕要比原版图书滞后一年的时间。当然,在外文图书购书渠道不畅通、读者的经济承受能力和外文水平有限等情况下,原著、译著都是很好的选择。
3. 如何选择作者、译者
  技术上的大牛未必能写出好书,但是好的作者肯定是技术的权威。就像W.Richard Stevens的一样,其三卷本的《TCP/IP详解》、两卷本的《UNIX网络编程》以及《UNIX环境高级编程》高级编程,全都是经典的传世之作。
译著的质量和原著的质量以及译者的水平都有很大的关系,蹩脚的译者翻译的书籍会增加阅读的难度,甚至曲解原著的意思。台湾候俊杰先生(http://www.csdn.net/expert/jjhou/有介绍)就是非常一位非常著名的译者,大陆尤晋元的Unix方面的图书、潘爱民的Com理论方面的图书也都是上上之选。
  作者和译者的选择,只能靠平时的经验积累和别人的推荐了。
4. 其他相关内容
  书籍的读者适用对象。每本书籍都有自己特定的读者对象,读者应该根据自己的实际情况适当地选择需要的图书。就像是清华大学出版社出版的谭浩强编写的《C语言程序设计》一书,照样有人说它是垃圾。是的,对于那些对于C语言了若指掌的那些人来说,该书就可以当成垃圾扔到一边了;但是对于新手学习C语言来说,这本书堪称是相当经典的教材了。
  书籍的厚薄。书是越厚越好么?有些读者会以为书越厚内容可能就越充实,书也就越权威;事实不尽其然。能深入者才能浅出,真正好的书籍并不需要大块头来装点自己的门面,能用简单通俗的语言深入浅出的把道理说明白,才是上选。动辄上千页的书,多久能看完都是个问题,这种书只适合作为技术手册,需要的时候搬来查一查。当然,要把内容详实地介绍清楚,还是需要一定的篇幅的。
  书籍的版次。从某种意义上来说,一本书的再版次数就反应了该书受欢迎的程度;至少也是再版修订过原来的错误了。计算机技术的发展可以用日新月异来形容,除了一些经典的介绍理论或基础的教材,读者应该尽量选购新版的书籍。
  书籍的多寡。并非手里面的书籍越多越好,这可能是读者的一个误区。就某一个专题来来说,可能有很多书都在讲解,但是在某一个阶段,适用于你的书有一本就足够了。在选书的时候就应该自习选择,拿到书后应该融会贯通;自己水平提高了,就可以换层次更高的书来看。不要妄想一本书里面会介绍所有的内容,这样的所谓大全只能是蜻蜓点水,让你全都一知半解。

  下面我们就Linux方面的图书做一个简单的介绍,希望能对读者选购图书有所帮助。(由于书籍实在太多,很多笔者也没看过,其内容和质量不敢妄加评论。) Linux从严格的技术定义讲,Linux指的是开放源代码的Unix类操作系统的内核。然而,目前大多数人用它来表示以Linux内核为基础的整个操作系统。Linux是一个自由的、开放的操作系统,其软件的发布和使用遵循GPL,现在在服务器、嵌入式应用等方面有突出的表现。Linux本身和Unix有千丝万缕的联系,其原理、应用有很多相通之处,因此可以触类旁通。
1. 系统安装和使用
  在早期众多的Linux发行版本中,最有影响的要数Slackware。当时它是最容易安装的Linux发行版本,在推广Linux的应用中,起了很大的作用。Linux文档项目(LDP)就是围绕Slackware发布写成的。目前,Red Hat发行版本的安装更容易,应用软件更多,已成为最流行的Linux发行版本;而Caldera则致力于Linux的商业应用,它的发展速度也很快。国内中文的发行版本有TurboLinux、红旗(RedFlag)Linux、蓝点(BluePoint)Linux、HappyLinux以及Xlinux。每种发行版本有各自的优点和弱点,但它们使用的内核和开发工具则是一致的,因此书籍的内容大部分也是相通的,读者在选购图书入门级的图书是没有必要限定于哪个发行版本。
  对于初学者我给大家推荐中国电力出版社2000年3月出版出版的《Linux权威指南》(第三版),原书由O'Reilly 出版,Matt Welsh,Matthias Kalle Dalheimer,Lar Kaufman著,洪峰译。该书内容设计系统安装,常用命令,系统管理,文件系统管理,Xwindow的定制和使用以及部分网络的内容,比较适合初学者使用。另外给大家介绍一本适合初学者使用的书,中国青年出版社引进的《精通Linux入门、管理与应用》(位元文化编著,台湾文魁资讯股份有限公司出版),这个书虽然块头很大(680页),但是排版比较松,内容深入浅出,比较适合我这样的懒人看。
  Linux上目前流行的两种GUI(图形用户界面)是KDE和GNOME,分别给大家推荐《实用KDE教程》(作者: Dennis E.Powell,译者: 张辉清华大学出版社,2000-11-1)和《轻松学用GNOME》(作者: David D.Busch,译者: 徐晓青 王江红 阎慧娟,电子工业出版社,2000-11-1)。这两本书分别介绍了KDE和GNOME的安装、使用,适合初学者使用。
  实际上Linux系统中的图形花引用软件并不比Windows逊色,比如GIMP(推荐书籍:《GIMP权威指南》,作者: Olof S.Kylander Karin Kylander,译者: 唐新桂 罗阿理 侯增广 冯兴元,机械工业出版社,2000-10-1)就可以和Photoshop抗衡;StarOffice是Linux系统中可以与Windows系统中的Office相媲美的软件,可惜国内市场上介绍StarOffice的书籍似乎没有。
  Linux上相当重要的一个部分就是网络,如果脱离开网络,其价值就大为降低了,以上书籍中对网络都有简单介绍,我们将在后面给出更详尽的书目进行介绍。
  目前在国内开展培训和认证考试的有TurboLinux、红旗和Xlinux,如果读者是要参加他们的认证考试,不妨参考一下各个公司出版的认证培训教材,见下表。

     发行版本

认证培训教材
TurboLinux        书名: 红旗Linux用户基础教程
作者: 中科红旗软件技术有限公司
页码: 288
定价: ¥26.00
出版社: 电子工业出版社
出版日期: 2001-1-1
书名: 红旗Linux网络管理教程
作者: 中科红旗软件技术有限公司
页码: 336
定价: ¥28.00
出版社: 电子工业出版社
出版日期: 2001-1-1
书名: 红旗Linux系统管理教程
作者: 中科红旗软件技术有限公司
页码: 348
定价: ¥28.00
出版社: 电子工业出版社
出版日期: 2001-1-1
XLinux

书名: Linux网络管理教程
作者: 北京网虎科技有限公司
页码: 218
定价: ¥26.00
出版社: 电子工业出版社
出版日期: 2001-4-1
书名: Linux系统管理教程
作者: 北京网虎科技有限公司
页码: 258
定价: ¥28.00
出版社: 电子工业出版社
出版日期: 2001-4-1


2. 系统管理和网络应用
  前面我们已经说过,Linux最主要的一个应用就是服务器,其稳定的性能、强大的网络功能深得用户的青睐。此处为大家推荐《GNU/Linux高级网络应用服务指南》(作者: LinuxAid网站,机械工业出版社,2001-1-1)。该书由国内非常出名的Linux的网站LinuxAid(http://www.linuxaid.com.cn)组织编写,参加编写的作者全部都是经验丰富的工程师,该书内容广泛,涉及到系统的安全优化策略、TCP/IP网络管理、Apache Web服务器、FTP服务器、邮件服务器、域名服务器、代理服务器、防火墙、路由器、拨号服务器、文件服务器、新闻组服务器、DHCP服务器、LDAP服务器、群集服务器、BBS、CVS以及系统安全软件的介绍。本书既适用于初级用户,也适用于高级用户。另外一本适用于中、高级用户的书是《Red Hat Linux系统管理员手册》(Mohammed J.Kabir著,魏永明、郑翔、孙登峰译,电子工业出版社,2000-7)。对于Solaris,推荐机械工业出版社的《Solaris系统管理员指南》(Janice Winsor著,王无敌等译,机械工业出版社,2000-1)和《Solaris高级系统管理员指南》(Janice Winsor著,王无敌等译,机械工业出版社,2000-2)。
  Linux上面的很多服务应用功能相当强大,种类繁多。看看《GNU/Linux高级网络应用服务指南》的目录就可以初见端倪了,但是这些服务的配置和使用并非一蹴而就,每个专题都会有大块头的书籍来介绍,高级用户应该转而看这些书了,以下我们就个别方面介绍一些比较好的书籍。
  Apache的功能相当强大,几乎是目前应用最广泛的Web服务器。与之相关的优秀的出版物也有不少,例如《Professional Apache》(Peter Wainwright著,Wrox Press Inc,1999-9)、《Linux Apache Web Server Administration (Linux Library)》(Charles Aulds著,Sybex,2000-9)等,国内市场能够见到一本好书的是《The Definitive Guide》(Ben Laurie、Peter Laurie著,O'Reilly,1999-2,中国电力出版影印,中文名《Apache 权威指南(第二版)》)。该书除了介绍Apache的安装、配置、使用之外,还介绍了Apache的一些API,以及如何编写Apache的模块(module),对系统管理员和编程人员都很有帮助。中文介绍Apache的图书给大家推荐《Apache Server实用全书》(英文原书名: Apache Server Unleashed ,作者: Rich Bowen Ken Coar 等,译者: 罗四维 等,电子工业出版社,出版日期: 2001-2-1)。
  Internet上每个进行通信的主机都要有自己的IP,但是人们更经常的是使用域名来访问主机,于是DNS就应运而生,实现IP地址和域名的转换。随着Internet的飞速膨胀,靠一台服务器来维护域名信息已经不可能,现在所依赖的BIND就是一种分布式数据库,它允许网络大规模无限制地增长下去。介绍DNS比较经典的书有《Linux DNS Server Administration (Craig Hunt Linux Library)》(Craig Hunt著,Sybex,2000-1)和《DNS and BIND (4th Edition)》(Paul Albitz、Cricket Liu著,O'Reilly,2001-4);后者的第三版中国电力出版社已经引进,中文名为《DNS与BIND》(雷迎春、陈世林、杨传军译,2000-11)。
  Linux中的邮件服务器采用的最多的是Sendmail,经典著作有《Linux Sendmail Administration (Craig Hunt Linux Library)》(Craig Hunt著,Sybex,2001-2)和《Sendmail》(Bryan Costales,Eric Allman著,O'Reilly,1997-1)。前者详尽地介绍了Sendmail的原理、安装、配置及安全性问题;后者的作者Eric Allman就是Sendmail的开发人员,中国电力出版社已经出版了该书的影印版,中文名为《sendmail》第二版(2000-5),上下两卷。
  Linux使用Samba和Windows之间实现共享访问,解释Samba比较好的书有《Using Samba》(Robert Eckstein,David Collier-Brown著,O'Reilly,1999-9)和《Linux Samba Server Administration》(Roderick W. Smith著,Sybex,2000-9)。二者都详细介绍了Samba的安装、配置、使用及安全性和备份、恢复的内容,前者已经被Samba小组正式采用,中国电力出版社已经引进并翻译出版了该书,中文名为《实战Samba》(薛彬等译,2001-1)。
  其他方面也都有专门的专著进行介绍,比如介绍NFS的《Managing NFS and NIS, 2nd Edition》(Hal Stern, Mike Eisler, Ricardo Labiaga著,O'Reilly,2001-7)和《Linux NFS and Automounter Administration》(Erez Zadok著,Sybex,2001-5),介绍SSH的《SSH, the Secure Shell : The Definitive Guide》(Daniel J. Barrett, Richard Silverman,O'Reilly,2001-2)等都是相当不错的书,读者可以根据需要自行选择。

3. 编程及开发应用
  Linux的内核主要使用C语言编写而成,少量地使用了汇编语言,其编译器采用gcc。因此C语言是Linux系统中相当重要的编程语言。都Linux编程很陌生的读者可以翻阅以下《GNU/Linux编程指南》(K.Wall M.Watson M.Whitis著,王勇、王一川、林花军、甘泉译,清华大学出版社,2000-6),该书对编程工具(GNU C、GNU Makefile、Autoconf、RCVS、Emacs)、系统编程(I/O操作、文件操作、进程、线程、内存管理)、进程间通信和网络编程(管道、消息队列、共享内存、信号灯、Socket、设备驱动程序)、用户界面编程(ncurses、Xlib、Motif、GTK、Qt、Java、OpenCL)、Shell编程及GDB调试工具都有简要的介绍,是了解Linux编程环境的一本好书,但是这本书的确是一本指南,每种技术都浅尝辄止,希望深入学习该技术的读者需要选择适当的书籍来学习。
  Linux中最基本的编程是Shell编程,推荐《LINUX与UNIX Shell编程指南》(David Tansley蓍,张春萌等译,机械工业出版社,2000-6),该书详细介绍了shell编程技巧,各种UNIX命令及语法,还涉及了UNIX下的文字处理以及少量的系统管理问题。
  系统编程推荐《UNIX环境高级编程》(W.Richard Stevens,尤晋元等译,机械工业出版社,2000-2),就是著名的APUE。本书对I/O、进程、信号、进程间通讯的介绍都相当深入,一直以来被誉为UNIX编程的"圣经",同样适用于Linux,翻译质量也属上乘。
网络编程推荐W.Richard Stevens的另外一套书:《UNIX网络编程》(清华大学出版社引进),大师的经典之作,赞美之词溢于言表。读者也可以参看国内出版的《Linux网络编程》(李卓桓等著,机械工业出版社,2000-1)。要想详细了解网络底层的知识,请看W.Richard Stevens的《TCP/IP详解》(三卷本,机械工业出版社)和DOUGLAS E.COMER的《用TCP/IP进行网际互连》(三卷本,电子工业出版社),这绝对是网络参考书中的经典。
  用户界面方面的编程工具比较多,ncurses是在终端下开发图形界面的有力工具;Xlib是构建Xwindow的基础,著名的KDE和GNOME分别就是使用QT和GTK开发的。这方面国内出版的书籍比较少,知道的有《Linux应用程序开发指南:使用Gtk+/Gnome库》(许宏松等著,机械工业出版社,2000-7)和《GNOME/GTK+编程宝典》(Arthur Griffith著,吴向峰、王景中、江继军等译,电子工业出版社,2000-12)。讲解QT的书有《Programming With Qt》(Matthias Kalle Dalheimer著,O'Reilly,1999-5),国内人民邮电出版社最近出版了一本《24小时精通QT编程》。
  目前Linux广泛使用的编程工具还有Perl、PHP等。Perl是一种解释性语言,从某种程度上来说可以替代CGI,比较好的书有《Programming Perl》(Larry Wall, Tom Christiansen, Jon Orwant著,O'Reilly,2000.1)、《Learning Perl》(Randal L. Schwartz, Tom Phoenix著,O'Reilly,2001.7),目前这两本书都已经出版到第三版,中国电力出版社已经引进翻译了后者,中文名为《Perl教程》(张大江译,2000-6)。PHP与Apache结合,在Web应用方面表现了巨大的潜力,推荐两本适合中、高级读者使用的书:《PHP 4.0 Web开发技术指南》(Tobias Ratschiller Till Gerken著,陈军、龙浩、李向荣译,机械工业出版社,2001-1)和《PHP4.x企业级Web应用与开发》(廖若雪等著,机械工业出版社,2001-4)。
  经验丰富的程序员都会知道源代码版本控制的重要性,Linux使用CVS来解决版本控制的问题。《CVS 开源软件开发技术》(Karl Fogel著,肖虎勤、陈军等译,机械工业出版社,2001-6)详细介绍CVS 的发展历史、基本概念、高级应用等内容。
  Linux对数据库应用的支持并不比Windows逊色,全部支持MySQL、Oracle、Informix、Sybase、DB2、Progress。《Linux环境数据库管理员指南》(David Egan著,钟鸣、田晓涛译,机械工业出版社,2001-1)全面地介绍了各种数据库在Linux下的安装、配置以及简单应用,这是唯一一本全面介绍Linux下数据库应用的书;可以想象的是,一本书里面全方位地介绍这么多数据库的内容,对数据库本身的知识介绍肯定不够,专著于数据库开发的读者需要结合所使用的数据库选择适当的图书,例如介绍MySQL的《MySQL网络数据库指南》(Paul DuBois著,田晓涛等译,机械工业出版社,2000-6)。
  如果读者希望了解内核的构造,不免会涉及的内核模块编程的问题,LKMPG(Linux Kernel Module Programming Guide)是LDP项目之一,一份比较权威的文档,其中译版收录在《Linux编程白皮书》(朱珂等译,机械工业出版社,2000-4)一书中,可惜的是原来是针对2.0.*版本的内核编写的,后来对2.2.*版本的内核进行了扩充,但是现在2.4.*版本的内核有和很大的改进,希望作者能早日更新本文档。
  在介绍了这么多编程系列的图书之后,最后再给大家推荐两本:《Beginning Linux Programming》(Neil Matthew, Richard Stones著,Wrox Press Inc,1999-9)和《Linux程序设计权威指南》(于明俭、陈向阳、方汉著,机械工业出版社,2001-4)。前者浙江大学曾组织影印过一批,从内容和涉及深度来讲,这本书可以看做是APUE的"入门"级版本,APUE虽然是学习Unix编程的经典,但对于初学者来说,显得太深,啃起来比较吃力,在这种情况下,BLP一书就很有阅读价值了。这本书从Linux编程的基本概念讲起, 覆盖了Shell编程、文件、环境、终端控制、Curses、进程与线程、管道、SystemV IPC、socket、Tcl/Tk、gtk+、Perl、HTML/CGI、设备驱动程序等Linux编程中常用的内容, 并介绍了make、版本控制等常用工具和Linux下C程序的调试技术。如果读者具有一般的C编程经验, 但以前没写过Linux程序,那么这本书可以帮助你很快迈入Linux编程的门坎。同时, 由于书中大多数章节内容严格遵循POSIX、XPG4I3(Unix98)、SVID等业界标准,因此也适合于学习一般的Unix编程。《Linux程序设计权威指南》的第一作者于明俭是chinput的作者,对Linux的国际化、本地化和中文化有很深入的研究,因此本书的第六章"国际化和中文化编程"应该是相当权威的。
4. 操作系统原理
  其实选择操作系统原理的书很简单,认一个人的名字就够了,Andrew S.Tanenbaum,他的《操作系统:设计与实现(第二版)》(两卷本,王鹏、尤晋元、朱鹏、敖青云译,电子工业出版社,2001-4)、《现代操作系统》(陈向群译,机械工业出版社,1999-10)、《分布式操作系统》(陆丽娜、伍卫国、刘隆国等译,电子工业出版社,1999-12)全都是经典之作,此处就不再介绍了。
5. 内核和源代码分析
  首先介绍的一本应该是《莱昂氏UNIX源代码分析》(John Lions著,尤晋元译,机械工业出版社,2000-9)。该书上篇为UNIX V6的源代码,下篇是莱昂先生对UNIX操作系统版本6源代码的详细分析。该书从1976年开始一直就是黑客内部流传的一部经典教材,直到1996年才得以正式出版。虽然内容很多涉及PDP11的内容,相应的汇编指令没有相应的基础很难看懂,但是本书的内容、思想永远都值得购买、学习。作者除了对源代码进行注释、分析之外,还提出了很多改进意见,china-pub把本书誉为旷世奇书实不过分。
对于Linux,国内出版了几本不错的书,其中最好的应该是陈莉君编著的《Linux操作系统内核分析》(人民邮电出版社,2000-8),该书对Linux内核进行了较全面的分析,既包括了对进程调度、内存管理、进程间通信、虚拟文件系统、设备驱动程序及网络子系统的分析,也包括对Linux整体结构的把握、Linux启动过程的剖析以及Linux独具特色的模块机制的分析与应用等。该书在台湾业界都广泛流传着复印或影印的版本;不足之处是内容深度不够,对SMP(对称多处理)等都没有介绍。
  译著里面值得一提的是机械工业出版社出版引进出版的姊妹篇:《Linux内核源代码分析》(Scott Maxwell著,冯锐、刑飞、刘隆国、陆丽娜译,2000-6)和《Linux IP协议栈源代码分析》(Stephen T.Satchell、H.B.J Clifford著,刘隆国、翟刚、陆丽娜、辛炜译,2000-11)。前者针对当时最新的内核(2.2.5),分析了系统初始化、系统调用、信号、中断和时间、进程和线程、内存、System V IPC、对称多处理等方面的内容。后者则是针对当时广泛被采用的2.0.34的内核的网络部分进行分析,较全面地介绍了ISO网络模型、API 、IP、ICMP以及ICP 等核心网络实现,对它们的代码进行了详尽的分析。但是在新版本的内核中(2.4.*)网络部分已经进行了相当大的改动,作者的第二版就是针对2.4.*版本的内核进行分析的。
  今年有一件令Linux的技术爱好者振奋人心的事情,就是《Understanding the LINUX Kernel: From I/O Ports to Process Management》(Daniel Pierre Bovet, Marco Cesati著,O'Reilly,2000-9)一书的出版,该书是迄今为止分析Linux内核最好的一本书;Solaris也出版了一本经典之作《Solaris Internals: Core Kernel Architecture》(Jim Mauro, Richard McDougall著,Prentice Hall PTR,2000-10)。这两本书已经分别由中国电力出版社和机械工业出版社引进,近期都会出版中译版。
  有关内核,网上公开的一份相当好的文档是LKI(Linux Kernel Internals),可惜的是还没有完成。另外有一本《Linux设备驱动程序》(Alessandro Ruibini著,LISOLEG译,中国电力出版社,2000-4)详细地介绍了Linux下开发设备驱动程序所涉及的内容,包括建立驱动程序并装载模块、完善字符设备、块设备和网络设备驱动程序、调试驱动程序、计时、内存管理和DMA、中断、可移植性事项、外部设备互连(PCI)、内核内幕的导览,是这方面不可多得的好书。可惜的是写第一版当时所采用的内核开发版本才到2.1.43,现在的2.4.*已经有了很大的改进,O'Reilly已经在今年6月份出版了本书的第二版,内容已经包含了2.4.*的改进,据说中国电力出版社已经引进了该书。
  还有很多优秀的图书,笔者可能不了解详情,不能一一列出;但愿这份简要的介绍能给读者选购图书提供帮助。

posted @ 2005-01-05 15:06 shimmer.rkfang 阅读(521) | 评论 (1)编辑

2004年12月20日 #

从10月份开始准备找工作到现在也过了两个多月了。可以的选择虽然不少,可实际去面的公司不多。面的公司中,也拿下了大半的offer。可一山望着一山高,总有写非常诱人的东西是没法拥有的。就像ATC。

嗯,啥也不说了,还是老老实实去上海吧。

posted @ 2004-12-20 10:07 shimmer.rkfang 阅读(130) | 评论 (0)编辑

2004年12月1日 #

     摘要: Introduction In this article, we’ll show a way to implement a simple software key that could be useful for protecting software components (e.g., EXE, DLL, COM, etc.) against misuse and for keeping track of installations. We want to highlight that this is just an example. We are aware that it is quite simple by-passing the protection offered by the software key presented in this article. However, we think that this article could be useful in allowing us to better understand the mechanisms   阅读全文
posted @ 2004-12-01 14:29 shimmer.rkfang 阅读(143) | 评论 (0)编辑

2004年10月10日 #

C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼。虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内存空间中又是如何布局的,却可以对C++的了解深入不少。这段时间花了一些时间了解这些玩意,搞得偶都,不过总算有些收获,嘿嘿。

先看一段代码
class A
{
      virtual aa(){};
};

class B : public virtual  A
{
      char j[3];                                    //加入一个变量是为了看清楚class中的vfptr放在什么位置
      public:
            virtual bb(){};
};
class C : public virtual B
{
      char i[3];
      public:
            virtual cc(){};
};

这次先不给结果,先分析一下,也好加强一下印象。
1、对于class A,由于只有一个虚函数,那么必须得有一个对应的虚函数表,来记录对应的函数入口地址。同时在class A的内存空间中之需要有个vfptr_A指向该表。sizeof(A)也很容易确定,为4。
2、对于class B,由于class B虚基础了class A,同时还拥有自己的虚函数。那么class B中首先拥有一个vfptr_B,指向自己的虚函数表。还有char j[3],做一次alignment,一般大小为4。可虚继承该如何实现咧?this is 啊 problem!偶之前是不晓得的,还好C++ Object Model上有介绍。首先要通过加入一个虚l类指针(记vbptr_B_A)来指向其父类,然后还要包含父类的所有内容。有些复杂了,不过还不难想象。sizeof(B)= 4+4+4+4=16(vfptr_B、char j[3]做alignment、vbptr_B_A和class A)。
3、在接着是class C了。class C首先也得有个vfptr_C,然后是char i[3],然后是vbptr_C_B,然后是class B,所以sizeof(C)=4+4+4+16=28(vfptr_C、char i[3]做alignment、vbptr_C_A和class B)。

在VC 6.0下写了个程序,把上面几个类的大小打印出来,果然结果为4、16、28。hoho搞定!真的搞定了?也许经过上面的分析,虽然每个类具体的内存布局还不大清楚,但其中的内容应该不会错了。嘿嘿,在没跟踪时偶确实也是这么想的,但结果却是……

VC中虚继承的内存布局——单继承
画了个图,简单表示一下我跟踪后的结果


虚基础之单继承时的内存布局图

class A的情况太简单,没问题。从class B的内存布局图可以得出下面的结论。
1、vf_ptr B放在了类的首部,那么如果要想直接拿memcpy完成类的复制是很危险的,用struct也是不行的。改天再深入学习一下struct 和class的区别,可以看出这里的差别来。
2、vbtbl_ptr_B,为什么不是先前我描述的vbptr_B_A呢?因为这个指针与我先前猜测的内容有很大区别。这个指针指向的是class B的虚类表(嗯,俺自个儿起的名字,实在是学艺不精)。看看VB table,VB table有两项,第一项为FFFFFFFC,这一项的值可能没啥意义,可能是为了保证虚类表不为空吧。第二项为8,看起来像是class B中的class A相对该vbtbl_ptr_B的位移,也就是一个offset。类似的方法在C++ Object Model(P121)有介绍,可以去看看。
class C的内存布局就比较复杂了,不过它的内存布局也更一步说明我对vbtbl_ptr_B中的内容,也就是虚类表的理解是正确的。不过值得关注的是class B中的class A在布局时被移到前面去了,虽然整个大小没变,但这样一来如果做这样的操作  C c; B *b;b=&c;时b的操作如何呢?此时只要从c的虚类表里获得class B的位置既可赋值给b。但是在构建class C时会复杂一些,后面的使用还是非常简单的,效率也比较高。class A的内存布局被前移可能是考虑倒C的虚继承顺序吧

结论
1、VC在编译时会把vfptr放到类的头部;
2、VC采用虚表指针(vbtbl_ptr)来确定某个类所继承的虚类。
3、VC会重新调整虚继承的父类在子类中内存布局。(具体规则还不清楚)
4、VC中虚类表中的第一项是无意义的,可能是为了保证sizeof(虚类表)!=0;后面的内容为父类在子类中相对该虚类表指针的偏移量。

目前看来虚继承在单一继承时的内存布局还是比较清晰的,不过多重继承呢?这就太bt了,简单的多重继承还没弄清楚呢,再来个虚继承,岂不只有。以后等俺有兴趣的时候,在找这事做吧。

posted @ 2004-10-10 18:41 shimmer.rkfang 阅读(1071) | 评论 (5)编辑

2004年10月9日 #

#include "iostream"
class A{
public:
    A(){
        std::cout<<"A::A()"<<std::endl;
    }
    A(const A&){
        std::cout<<"A::A(const A&)"<<std::endl;
    }
    A(int){
  std::cout<<"A::A(int)"<<std::endl;
    }  
}; 

A test(){
    return A::A(1);
}

void main(void)
{
    std::cout<<"hello!"<<std::endl;
    A c = test();
}

vc6.0下的结果是:
A::A(int)
A::A(const A&)
A::A(const A&)
 

猜测的编译器vc6处理后的伪码:
//////////////////////////////////////////////////////////////////////////
//test函数会根据返回值为对象初始化的原则进行编译处理
test(A &__result)   //返回值初始化
{
 A tmp;          //编译器处理后,不做初始化

 tmp.A::A(1); 
 __result.A::A(&tmp);
 return;
}
//返回值为对象初始化原则:
//1、首先加上一个额外参数,类型为函数的reference。用来放置被“拷贝构造”而得得返回值;
//2、再return指令之前插入一个copy constructor调用操作,将欲传回的对象内容当作上述新增参数的初值;

//main函数中的关键代码被编译后生产的伪代码
{
 A c=test();   ->

 A tmp;            //编译器处理后,不做初始化
 test(tmp);
 A c;
 c.A::A(tmp);   //编译器处理后,不做初始化
 
}

//看了一下vc编译出来得汇编码,可以确定上面的伪码是正确的。vc的做法和C++ object model上描述的共同点在于:
1、返回值初始化的处理是一致的。ps:huhu,总算一致了一盘,真是个麻烦的冬冬。
2、对于返回值为对象的函数可能都做了一个临时对象tmp来处理。否则可以把A c=test();编译成A c; test(c),这样就可以少一次copy constructor的调用操作了。

//唉唉,看了三天的C++ object model,虽然令我对C++有了深一点点的认识,但一遇到新的内容就没法考虑了。C++的bt是一个原因,编译器的实现又各不相同,实在是会导致无法预知的结果。最好的办法就是背台笔记本,每次都把调试信息打印出来,那就一切清净了。

还要好好学习啊。C++,“O,O,O”,这是俺最近的目标。

可以去看看相关的文章:关于拷贝构造函数和赋值运算符

posted @ 2004-10-09 18:14 shimmer.rkfang 阅读(241) | 评论 (0)编辑