﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Welcome to ErranLi's Blog!</title><link>http://www.cppblog.com/erran/</link><description /><language>zh-cn</language><lastBuildDate>Sun, 05 Jul 2009 20:57:25 GMT</lastBuildDate><pubDate>Sun, 05 Jul 2009 20:57:25 GMT</pubDate><ttl>60</ttl><item><title>ARM &amp; DSP 。。。。。。。。。</title><link>http://www.cppblog.com/erran/archive/2008/07/20/56671.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sun, 20 Jul 2008 03:41:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2008/07/20/56671.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/56671.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2008/07/20/56671.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/56671.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/56671.html</trackback:ping><description><![CDATA[ <br />想买套嵌入式的硬件玩玩，查了很长时间的资料，确定了两个方面arm，dsp。公司做的东西主要用到的是dsp，惭愧的做软件的没什么机会接触那些。<br /><br />看了arm和dsp的比较，arm对操作系统的支持很好，控制性能很好，dsp的数据处理能力......<br /><br />想先买个arm板试试，考虑了很久最后还是决定买周立功的，虽然价格贵了点，资料全些。 MagicARM2410没查到价钱，估计在5k以上吧，没法接受..... smartArm2200不到2k，勉强还行。。<br /><br />今天是星期日，打他们代理电话，说只能周一到周五才能买到，晕死，周立功不会这么牛吧......还有这样做生意的。。。。。<br /><br />《打听到的DSP价格 SEED-XDSusbUSB2.0（1.7k含税公司采购价） SEED-DPS2812/Kit（1.5k左右吧） 》<br /><br /><br />这里应该有很多是做这个的吧，毕竟是Cpp blog， o(∩_∩)o... 恳请给点建议....<br /><br />《《《不好意思，我发到了“首页原创区”，谅解啊 o(∩_∩)o...》》》》<br /><img src ="http://www.cppblog.com/erran/aggbug/56671.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2008-07-20 11:41 <a href="http://www.cppblog.com/erran/archive/2008/07/20/56671.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：字节对齐详解</title><link>http://www.cppblog.com/erran/archive/2007/10/16/34383.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Tue, 16 Oct 2007 14:56:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/16/34383.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34383.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/16/34383.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34383.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34383.html</trackback:ping><description><![CDATA[
		<br />看了这篇（http://www.cppblog.com/Randy/archive/2007/10/15/34288.aspx）关于字节对其的随笔，觉得迷迷糊糊的，脑袋里只有字节对其这个概念，具体都忘的差不多了，又另外找了篇细读了下，总算理解了。<br /><br />来源：http://www.yuanma.org/data/2006/0723/article_1213.htm<br /><h3>一.什么是字节对齐,为什么要对齐?</h3><p>   
现代计算机中内存空间都是按照byte划分的，从理论上讲似乎对任何类型的变量的访问可以从任何地址开始，但实际情况是在访问特定类型变量的时候经常在特
定的内存地址访问，这就需要各种类型数据按照一定的规则在空间上排列，而不是顺序的一个接一个的排放，这就是对齐。<br />   
对齐的作用和原因：各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问
一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况，但是最常见的是如果不按照适合其平台要求对
数据存放进行对齐，会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始，如果一个int型（假设为32位系统）如果存放在偶地址开始的地方，那
么一个读周期就可以读出这32bit，而如果存放在奇地址开始的地方，就需要2个读周期，并对两次读出的结果的高低字节进行拼凑才能得到该32bit数
据。显然在读取效率上下降很多。</p><h3>二.字节对齐对程序的影响:</h3><p>    先让我们看几个例子吧(32bit,x86环境,gcc编译器):<br />设结构体如下定义：<br />struct A<br />{<br />    int a;<br />    char b;<br />    short c;<br />};<br />struct B<br />{<br />    char b;<br />    int a;<br />    short c;<br />};<br />现在已知32位机器上各种数据类型的长度如下:<br />char:1(有符号无符号同)    <br />short:2(有符号无符号同)    <br />int:4(有符号无符号同)    <br />long:4(有符号无符号同)    <br />float:4    double:8<br />那么上面两个结构大小如何呢?<br />结果是:<br />sizeof(strcut A)值为8<br />sizeof(struct B)的值却是12</p><p>结构体A中包含了4字节长度的int一个，1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字节。<br />之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。上面是按照编译器的默认设置进行对齐的结果,那么我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如:<br />#pragma pack (2) /*指定按2字节对齐*/<br />struct C<br />{<br />    char b;<br />    int a;<br />    short c;<br />};<br />#pragma pack () /*取消指定对齐，恢复缺省对齐*/<br />sizeof(struct C)值是8。<br />修改对齐值为1：<br />#pragma pack (1) /*指定按1字节对齐*/<br />struct D<br />{<br />    char b;<br />    int a;<br />    short c;<br />};<br />#pragma pack () /*取消指定对齐，恢复缺省对齐*/<br />sizeof(struct D)值为7。<br />后面我们再讲解#pragma pack()的作用.</p><h3>三.编译器是按照什么样的原则进行对齐的?</h3><p>    先让我们看四个重要的基本概念：<br /><font color="#0000ff">1.数据类型自身的对齐值：<br /></font>  对于char型数据，其自身对齐值为1，对于short型为2，对于int,float,double类型，其自身对齐值为4，单位字节。<br /><font color="#3300ff">2.结构体或者类的自身对齐值：</font>其成员中自身对齐值最大的那个值。<br /><font color="#0000ff">3.指定对齐值</font>：#pragma pack (value)时的指定对齐值value。<br /><font color="#0000ff">4.数据成员、结构体和类的有效对齐值：</font>自身对齐值和指定对齐值中小的那个值。<br />有
了这些值，我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值，最重要。有效对齐N，就是
表示“对齐在N上”，也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数
据结构的起始地址。结构体的成员变量要对齐排放，结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数
倍，结合下面例子理解)。这样就不能理解上面的几个例子的值了。<br />例子分析：<br />分析例子B；<br />struct B<br />{<br />    char b;<br />    int a;<br />    short c;<br />};<br />假
设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值，在笔者环境下，该值默认为4。第一个成员变量b的自身对齐值是1，比指定或者默认指定
对齐值4小，所以其有效对齐值为1，所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a，其自身对齐值为4，所以有效对齐值也为4，
所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中，复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为
2，所以有效对齐值也是2，可以存放在0x0008到0x0009这两个字节空间中，符合0x0008%2=0。所以从0x0000到0x0009存放的
都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b）所以就是4，所以结构体的有效对齐值也是4。根据结构体圆整的要求，
0x0009到0x0000=10字节，（10＋2）％4＝0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B
共有12个字节,sizeof(struct B)=12;<font color="#3300ff">其实如果就这一个就来说它已将满足字节对齐了,
因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那
么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一
个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.其实诸如:对于char型数据，其
自身对齐值为1，对于short型为2，对于int,float,double类型，其自身对齐值为4，这些已有类型的自身对齐值也是基于数组考虑的,只
是因为这些类型的长度已知了,所以他们的自身对齐值也就已知了.<br /></font>同理,分析上面例子C：<br />#pragma pack (2) /*指定按2字节对齐*/<br />struct C<br />{<br />    char b;<br />    int a;<br />    short c;<br />};<br />#pragma pack () /*取消指定对齐，恢复缺省对齐*/<br />第
一个变量b的自身对齐值为1，指定对齐值为2，所以，其有效对齐值为1，假设C从0x0000开始，那么b存放在0x0000，符合0x0000%1=
0;第二个变量，自身对齐值为4，指定对齐值为2，所以有效对齐值为2，所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续
字节中，符合0x0002%2=0。第三个变量c的自身对齐值为2，所以有效对齐值为2，顺序存放<br />在0x0006、0x0007中，符合
0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。又C的自身对齐值为4，所以C的有效对齐值为2。又8%2=0,C
只占用0x0000到0x0007的八个字节。所以sizeof(struct C)=8.</p><h3>四.如何修改编译器的默认对齐值?</h3><p>1.在VC IDE中，可以这样修改：[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改，默认是8字节。<br />2.在编码时，可以这样动态修改：#pragma pack .<font color="#ff0000">注意:是pragma而不是progma.</font></p><h3>五.针对字节对齐,我们在编程中如何考虑?</h3><p><br />   
如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照
类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做
法是显式的插入reserved成员：<br />         struct A{<br />           char a;<br />           char reserved[3];//使用空间换时间<br />           int b;<br />}<br /><br />reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用.</p><h3>六.字节对齐可能带来的隐患:</h3><p>    代码中关于对齐的隐患，很多是隐式的。比如在强制类型转换的时候。例如：<br />unsigned int i = 0x12345678;<br />unsigned char *p=NULL;<br />unsigned short *p1=NULL;</p><p>p=&amp;i;<br />*p=0x00;<br />p1=(unsigned short *)(p+1);<br />*p1=0x0000;<br />最后两句代码，从奇数边界去访问unsignedshort型变量，显然不符合对齐的规定。<br />在x86上，类似的操作只会影响效率，但是在MIPS或者sparc上，可能就是一个error,因为它们要求必须字节对齐.</p><h3>七.如何查找与字节对齐方面的问题:</h3><p>如果出现对齐或者赋值问题首先查看<br />1. 编译器的big little端设置<br />2. 看这种体系本身是否支持非对齐访问<br />3. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作。</p><p>八.相关文章:转自<a href="http://blog.csdn.net/goodluckyxl/archive/2005/10/17/506827.aspx"><u>http://blog.csdn.net/goodluckyxl/archive/2005/10/17/506827.aspx</u></a></p><quote></quote><p> ARM下的对齐处理 <br />from DUI0067D_ADS1_2_CompLib </p><p>3.13 type  qulifiers </p><p>有部分摘自ARM编译器文档对齐部分</p><p>对齐的使用:<br />1.__align(num)<br />   这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时<br />   就要用到此命令__align(8)进行修饰限制。来保证数据对象是相应对齐。<br />   这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节<br />   对齐,但是不能让4字节的对象2字节对齐。<br />   __align是存储类修改,他只修饰最高级类型对象不能用于结构或者函数对象。<br />   <br />2.__packed <br />  __packed是进行一字节对齐<br />  1.不能对packed的对象进行对齐<br />  2.所有对象的读写访问都进行非对齐访问<br />  3.float及包含float的结构联合及未用__packed的对象将不能字节对齐<br />  4.__packed对局部整形变量无影响<br />  5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定<br />  义为packed。<br />     __packed int* p;  //__packed int 则没有意义<br />  6.对齐或非对齐读写访问带来问题<br />  __packed struct STRUCT_TEST<br /> {<br />  char a;<br />  int b;<br />  char c;<br /> }  ;    //定义如下结构此时b的起始地址一定是不对齐的<br />         //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL]<br />//将下面变量定义成全局静态不在栈上 <br />static char* p;<br />static struct STRUCT_TEST a;<br />void Main()<br />{<br /> __packed int* q;  //此时定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以</p><p> p = (char*)&amp;a;          <br /> q = (int*)(p+1);      <br /> <br /> *q = 0x87654321; <br />/*   <br />得到赋值的汇编指令很清楚<br />ldr      r5,0x20001590 ; = #0x12345678<br />[0xe1a00005]   mov      r0,r5<br />[0xeb0000b0]   bl       __rt_uwrite4  //在此处调用一个写4byte的操作函数 <br />      <br />[0xe5c10000]   strb     r0,[r1,#0]   //函数进行4次strb操作然后返回保证了数据正确的访问<br />[0xe1a02420]   mov      r2,r0,lsr #8<br />[0xe5c12001]   strb     r2,[r1,#1]<br />[0xe1a02820]   mov      r2,r0,lsr #16<br />[0xe5c12002]   strb     r2,[r1,#2]<br />[0xe1a02c20]   mov      r2,r0,lsr #24<br />[0xe5c12003]   strb     r2,[r1,#3]<br />[0xe1a0f00e]   mov      pc,r14<br />*/</p><p>/*<br />如果q没有加__packed修饰则汇编出来指令是这样直接会导致奇地址处访问失败<br />[0xe59f2018]   ldr      r2,0x20001594 ; = #0x87654321<br />[0xe5812000]   str      r2,[r1,#0]<br />*/</p>//这样可以很清楚的看到非对齐访问是如何产生错误的<br />//以及如何消除非对齐访问带来问题<br />//也可以看到非对齐访问和对齐访问的指令差异导致效率问题<br />}<br /><img src ="http://www.cppblog.com/erran/aggbug/34383.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-16 22:56 <a href="http://www.cppblog.com/erran/archive/2007/10/16/34383.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：一个老工程师的话</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34191.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:55:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34191.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34191.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34191.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34191.html</trackback:ping><description><![CDATA[ 诸位，咱当电子工程师也是十余年了，不算有出息，环顾四周，也没有看见几个有出息的！回顾工程师生涯，感慨万千，愿意讲几句掏心窝子的话，也算给咱们师弟师妹们提个醒，希望他们比咱们强！<br /> <br />[1]
好好规划自己的路，不要跟着感觉走！根据个人的理想决策安排，绝大部分人并不指望成为什么院士或教授，而是希望活得滋润一些，爽一些。那么，就需要慎重安
排自己的轨迹。从哪个行业入手，逐渐对该行业深入了解，不要频繁跳槽，特别是不要为了一点工资而转移阵地，从长远看，这点钱根本不算什么，当你对一个行业
有那么几年的体会，以后钱根本不是问题。频繁地动荡不是上策，最后你对哪个行业都没有摸透，永远是新手！<br /> <br />[2]可以做技术，切不可沉湎于技术。千万不可一门心思钻研技术！给自己很大压力，如果你的心思全部放在这上面，那么注定你将成为孔乙己一类的人物！适可而止为之，因为技术只不过是你今后前途的支柱之一，而且还不是最大的支柱。<br /> <br />[3]
不要去做技术高手，只去做综合素质高手！在企业里混，我们时常瞧不起某人，说他“什么都不懂，凭啥拿那么多钱，凭啥升官！”这是普遍的典型的工程师的迂腐
之言。8051很牛吗？人家能上去必然有他的本事，而且是你没有的本事。你想想，老板搞经营那么多年，难道见识不如你这个新兵？人家或许善于管理，善于领
会老板意图，善于部门协调等等。因此务必培养自己多方面的能力，包括管理，亲和力，察言观色能力，攻关能力等，要成为综合素质的高手，则前途无量，否则只
能躲在角落看示波器！技术以外的技能才是更重要的本事！！从古到今，美国日本，一律如此！<br /> <br />[4]多交社会三教九流的朋友！不要只和工程
师交往，认为有共同语言，其实更重要的是和其他类人物交往，如果你希望有朝一日当老板或高层管理，那么你整日面对的就是这些人。了解他们的经历，思维习
惯，爱好，学习他们处理问题的模式，了解社会各个角落的现象和问题，这是以后发展的巨大的本钱。<br /> <br />[6]抓住时机向技术管理或市场销售方
面的转变！要想有前途就不能一直搞开发，适当时候要转变为管理或销售，前途会更大，以前搞技术也没有白搞，以后还用得着。搞管理可以培养自己的领导能力，
搞销售可以培养自己的市场概念和思维，同时为自己以后发展积累庞大的人脉！应该说这才是前途的真正支柱！<br /> <br />[7]逐渐克服自己的心里弱点
和性格缺陷！多疑，敏感，天真（贬义，并不可爱），犹豫不决，胆怯，多虑，脸皮太薄，心不够黑，教条式思维。。。这些工程师普遍存在的性格弱点必须改变！
很难吗？只在床上想一想当然不可能，去帮朋友守一个月地摊，包准有效果，去实践，而不要只想！不克服这些缺点，一切不可能，甚至连项目经理都当不好--尽
管你可能技术不错！<br /> <br />[8]工作的同时要为以后做准备！建立自己的工作环境！及早为自己配置一个工作环境，装备电脑，示波器（可以买个二
手的），仿真器，编程器等，业余可以接点活，一方面接触市场，培养市场感觉，同时也积累资金，更重要的是准备自己的产品，咱搞技术的没有钱，只有技术，技
术的代表不是学历和证书，而是产品，拿出象样的产品，就可技术转让或与人合作搞企业！先把东西准备好，等待机会，否则，有了机会也抓不住！<br /> <br />[9]
要学会善于推销自己！不仅要能干，还要能说，能写，善于利用一切机会推销自己，树立自己的品牌形象，很必要！要创造条件让别人了解自己，不然老板怎么知道
你能干？外面的投资人怎么相信你？提早把自己推销出去，机会自然会来找你！搞个个人主页是个好注意！！特别是培养自己在行业的名气，有了名气，高薪机会自
不在话下，更重要的是有合作的机会...... <br /><br />[10]该出手时便出手！永远不可能有100%把握！！！条件差不多就要大胆去干，去闯出自己的事业，不要犹豫，不要彷徨，干了不一定成功，但至少为下一次冲击积累了经验，不干永远没出息，而且要干成必然要经历失败。不经历风雨，怎么见彩虹，没有人能随随便便成功！<img src ="http://www.cppblog.com/erran/aggbug/34191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:55 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：单片机汇编程序编码规范</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34188.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:43:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34188.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34188.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34188.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34188.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34188.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 单片机汇编程序编码规范																																		http://www.blogcn.com/u2/94/42/cbz6000/blog/43716860.html																																						引言										    		...&nbsp;&nbsp;<a href='http://www.cppblog.com/erran/archive/2007/10/14/34188.html'>阅读全文</a><img src ="http://www.cppblog.com/erran/aggbug/34188.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:43 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34188.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中的一些常用方法</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34185.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:38:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34185.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34185.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34185.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34185.html</trackback:ping><description><![CDATA[
		<font face="Arial">
				<br />
				<strong>一、打开CD-ROM <br /></strong>mciSendString("Set cdAudio door open wait",NULL,0,NULL); <br /><br /><strong>二、关闭CD_ROM</strong> <br />mciSendString("Set cdAudio door closed wait",NULL,0,NULL); <br /><br /><strong>三、关闭计算机 <br /></strong>OSVERSIONINFO OsVersionInfo; //包含操作系统版本信息的数据结构 <br />OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); <br />GetVersionEx(&amp;OsVersionInfo); //获取操作系统版本信息 <br />if(OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) <br />{ <br />//Windows98,调用ExitWindowsEx()函数重新启动计算机 <br /><br />DWORD dwReserved; <br />ExitWindowsEx(EWX_REBOOT,dwReserved); //可以改变第一个参数，实现注销用户、 <br />//关机、关闭电源等操作 <br />// 退出前的一些处理程序 <br />} <br /><br /><strong>四、重启计算机 <br /></strong>typedef int (CALLBACK *SHUTDOWNDLG)(int); //显示关机对话框函数的指针 <br />HINSTANCE hInst = LoadLibrary("shell32.dll"); //装入shell32.dll <br />SHUTDOWNDLG ShutDownDialog; //指向shell32.dll库中显示关机对话框函数的指针 <br />if(hInst != NULL) <br />{ <br />//获得函数的地址并调用之 <br />ShutDownDialog = (SHUTDOWNDLG)GetProcAddress(hInst,(LPSTR)60); <br /><br />(*ShutDownDialog)(0); <br />} <br /><br /><strong>五、枚举所有字体 <br /></strong>LOGFONT lf; <br />lf.lfCharSet = DEFAULT_CHARSET; // Initialize the LOGFONT structure <br />strcpy(lf.lfFaceName,""); <br />CClientDC dc (this); <br />// Enumerate the font families <br />::EnumFontFamiliesEx((HDC) dc,&amp;lf,                                                                                       <br />(FONTENUMPROC) EnumFontFamProc,(LPARAM) this,0); <br />//枚举函数 <br />int CALLBACK EnumFontFamProc(LPENUMLOGFONT lpelf, <br />LPNEWTEXTMETRIC lpntm,DWORD nFontType,long lparam) <br /><br />{ <br />// Create a pointer to the dialog window <br />CDay7Dlg* pWnd = (CDay7Dlg*) lparam; <br />// add the font name to the list box <br />pWnd -&gt;m_ctlFontList.AddString(lpelf -&gt;elfLogFont.lfFaceName); <br />// Return 1 to continue font enumeration <br />return 1; <br />} <br />其中m_ctlFontList是一个列表控件变量 <br /><br /><strong>六、一次只运行一个程序实例，如果已运行则退出</strong> <br />if( FindWindow(NULL,"程序标题")) exit(0); <br /><br /><strong>七、得到当前鼠标所在位置</strong> <br />CPoint pt; <br />GetCursorPos(&amp;pt); //得到位置 <br /><br /><strong>八、上下文菜单事件触发事件：OnContextMenu事件 <br /></strong><br /><strong>九、显示和隐藏程序菜单 <br /></strong>CWnd *pWnd=AfxGetMainWnd(); <br />if(b_m) //隐藏菜单 <br />{ <br />pWnd-&gt;SetMenu(NULL); <br />pWnd-&gt;DrawMenuBar(); <br />b_m=false; <br />} <br />else <br />{ <br />CMenu menu; <br />menu.LoadMenu(IDR_MAINFRAME); ////显示菜单 也可改变菜单项 <br />pWnd-&gt;SetMenu(&amp;menu); <br />pWnd-&gt;DrawMenuBar(); <br />b_m=true; <br />menu.Detach(); <br />} <br /><br /><strong>十、获取可执行文件的图标</strong> <br />HICON hIcon=::ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0); <br />if (hIcon &amp;&amp;hIcon!=(HICON)-1) <br />{ <br />pDC-&gt;DrawIcon(10,10,hIcon); <br /><br />} <br />DestroyIcon(hIcon); <br /><br /><strong>十一、窗口自动靠边程序演示</strong> <br />BOOL AdjustPos(CRect* lpRect) <br />{//自动靠边 <br />int iSX=GetSystemMetrics(SM_CXFULLSCREEN); <br />int iSY=GetSystemMetrics(SM_CYFULLSCREEN); <br />RECT rWorkArea; <br />BOOL bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT), &amp;rWorkAre <br />a, 0); <br />CRect rcWA; <br />if(!bResult) <br />{//如果调用不成功就利用GetSystemMetrics获取屏幕面积 <br />rcWA=CRect(0,0,iSX,iSY); <br />} <br />else <br />rcWA=rWorkArea; <br />int iX=lpRect-&gt;left; <br />int iY=lpRect-&gt;top; <br /><br />if(iX &lt; rcWA.left + DETASTEP &amp;&amp; iX!=rcWA.left) <br />{//调整左 <br />//pWnd-&gt;SetWindowPos(NULL,rcWA.left,iY,0,0,SWP_NOSIZE); <br />lpRect-&gt;OffsetRect(rcWA.left-iX,0); <br />AdjustPos(lpRect); <br />return TRUE; <br />} <br />if(iY &lt; rcWA.top + DETASTEP &amp;&amp; iY!=rcWA.top) <br />{//调整上 <br />//pWnd-&gt;SetWindowPos(NULL ,iX,rcWA.top,0,0,SWP_NOSIZE); <br />lpRect-&gt;OffsetRect(0,rcWA.top-iY); <br />AdjustPos(lpRect); <br />return TRUE; <br />} <br />if(iX + lpRect-&gt;Width() &gt; rcWA.right - DETASTEP &amp;&amp; iX !=rcWA.right-lpRect-&gt;W <br /><br />idth()) <br />{//调整右 <br />//pWnd-&gt;SetWindowPos(NULL ,rcWA.right-rcW.Width(),iY,0,0,SWP_NOSIZE); <br />lpRect-&gt;OffsetRect(rcWA.right-lpRect-&gt;right,0); <br />AdjustPos(lpRect); <br />return TRUE; <br />} <br />if(iY + lpRect-&gt;Height() &gt; rcWA.bottom - DETASTEP &amp;&amp; iY !=rcWA.bottom-lpRect <br />-&gt;Height()) <br />{//调整下 <br />//pWnd-&gt;SetWindowPos(NULL ,iX,rcWA.bottom-rcW.Height(),0,0,SWP_NOSIZE); <br />lpRect-&gt;OffsetRect(0,rcWA.bottom-lpRect-&gt;bottom); <br />return TRUE; <br />} <br />return FALSE; <br />} <br />//然后在ONMOVEING事件中使用所下过程调用 <br /><br />CRect r=*pRect; <br />AdjustPos(&amp;r); <br />*pRect=(RECT)r; <br /><br /><strong>十二、给系统菜单添加一个菜单项 <br /></strong>给系统菜单添加一个菜单项需要进行下述三个步骤： <br />首先，使用Resource Symbols对话（在View菜单中选择Resource Symbols．．．可以显 <br />示该对话）定义菜单项ID，该ID应大于0x0F而小于0xF000； <br />其次，调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单 <br />项添加到菜单中。下例给系统菜单添加两个新的 <br />int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct) <br />{ <br />… <br />//Make sure system menu item is in the right range. <br /><br />ASSERT(IDM_MYSYSITEM&lt;0xF000); <br />//Get pointer to system menu. <br />CMenu* pSysMenu=GetSystemMenu(FALSE); <br />ASSERT_VALID(pSysMenu); <br />//Add a separator and our menu item to system menu. <br />CString StrMenuItem(_T ("New menu item")); <br />pSysMenu-&gt;AppendMenu(MF_SEPARATOR); <br />pSysMenu-&gt;AppendMenu(MF_STRING, IDM_MYSYSITEM, StrMenuItem); <br />… <br />} <br /><br /><strong>十三、运行其它程序</strong> <br />//1、运行EMAIL或网址 <br />char szMailAddress[80]; <br />strcpy(szMailAddress,"mailto:netvc@21cn.com"); <br />ShellExecute(NULL, "open", szMailAddress, NULL, NULL, SW_SHOWNORMAL); <br /><br />//2、运行可执行程序 <br />WinExec("notepad.exe",SW_SHOW); //运行计事本 <br /><br /><strong>十四、动态增加或删除菜单 <br /></strong>1、 增加菜单 <br />//添加 <br />CMenu *mainmenu; <br />mainmenu=AfxGetMainWnd()-&gt;GetMenu(); //得到主菜单 <br />(mainmenu-&gt;GetSubMenu (0))-&gt;AppendMenu (MF_SEPARATOR);//添加分隔符 <br />(mainmenu-&gt;GetSubMenu (0))-&gt;AppendMenu(MF_STRING,ID_APP_ABOUT,_T("Always on <br />&amp;Top")); //添加新的菜单项 <br />DrawMenuBar(); //重画菜单 <br />2、 删除菜单 <br />//删除 <br />CMenu *mainmenu; <br />mainmenu=AfxGetMainWnd()-&gt;GetMenu(); //得到主菜单 <br /><br />CString str ; <br />for(int i=(mainmenu-&gt;GetSubMenu (0))-&gt;GetMenuItemCount()-1;i&gt;=0;i--) //取得菜 <br />单的项数。 <br />{ <br />(mainmenu-&gt;GetSubMenu (0))-&gt;GetMenuString(i,str,MF_BYPOSITION); <br />//将指定菜单项的标签拷贝到指定的缓冲区。MF_BYPOSITION的解释见上。 <br />if(str=="Always on &amp;Top") //如果是刚才我们增加的菜单项，则删除。 <br />{ <br />(mainmenu-&gt;GetSubMenu (0))-&gt;DeleteMenu(i,MF_BYPOSITION); <br />break; <br />} <br /><br /><strong>十五、改变应用程序的图标</strong> <br />静态更改： 修改图标资源IDR_MAINFRAME。它有两个图标，一个是16*16的，另一个是3 <br /><br />2*32的，注意要一起修改。 <br />动态更改： 向主窗口发送WM_SETICON消息.代码如下： <br />HICON hIcon=AfxGetApp()-&gt;LoadIcon(IDI_ICON); <br />ASSERT(hIcon); <br />AfxGetMainWnd()-&gt;SendMessage(WM_SETICON,TRUE,(LPARAM)hIcon); <br /><br /><strong>十六、另一种改变窗口标题的方法</strong> <br />使用语句 CWnd* m_pCWnd = AfxGetMainWnd( )，然后，再以如下形式调用SetWindowTe <br />xt()函数： <br />SetWindowText( *m_pCWnd,(LPCTSTR)m_WindowText)；// m_WindowText可以是一个CSt <br />ring类的变量。 <br /><br /><strong>十七、剪切板上通过增强元文件拷贝图像数据 <br /></strong>下面代码拷贝通过元文件拷贝图像数据到任何应用程序，其可以放置在CView派生类的函 <br /><br />数中。 <br />CMetaFileDC * m_pMetaDC = new CMetaFileDC(); <br />m_pMetaDC-&gt;CreateEnhanced(GetDC(),NULL,NULL,"whatever"); <br />//draw meta file <br />//do what ever you want to do: bitmaps, lines, text... <br />//close meta file dc and prepare for clipboard; <br />HENHMETAFILE hMF = m_pMetaDC-&gt;CloseEnhanced(); <br />//copy to clipboard <br />OpenClipboard(); <br />EmptyClipboard(); <br />::SetClipboardData(CF_ENHMETAFILE,hMF);                                                                                 <br />CloseClipboard(); <br /><br />//DeleteMetaFile(hMF); <br />delete m_pMetaDC; <br /><br /><strong>十八、剪切板上文本数据的传送</strong> <br />把文本放置到剪接板上： <br />CString source; <br />//put your text in source <br />if(OpenClipboard()) <br />{ <br />HGLOBAL clipbuffer; <br />char * buffer; <br />EmptyClipboard(); <br />clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1); <br />buffer = (char*)GlobalLock(clipbuffer); <br />strcpy(buffer, LPCSTR(source)); <br />GlobalUnlock(clipbuffer); <br />SetClipboardData(CF_TEXT,clipbuffer); <br />CloseClipboard(); <br />} <br />从剪接板上获取文本： <br /><br />char * buffer; <br />if(OpenClipboard()) <br />{ <br />buffer = (char*)GetClipboardData(CF_TEXT); <br />//do something with buffer here <br />//before it goes out of scope <br />} <br />CloseClipboard(); <br /><br /><strong>十九、将捕捉屏幕图像到剪切版中 <br /></strong>void CShowBmpInDlgDlg::OnCutScreen() <br />{ <br />ShowWindow(SW_HIDE); <br />RECT r_bmp={0,0,::GetSystemMetrics(SM_CXSCREEN), <br />::GetSystemMetrics(SM_CYSCREEN)};                                                                                       <br />HBITMAP hBitmap; <br />hBitmap=CopyScreenToBitmap(&amp;r_bmp); <br /><br />//hWnd为程序窗口句柄 <br />if (OpenClipboard()) <br />{ <br />EmptyClipboard(); <br />SetClipboardData(CF_BITMAP, hBitmap); <br />CloseClipboard(); <br />} <br />ShowWindow(SW_SHOW); <br />} <br />HBITMAP CShowBmpInDlgDlg::CopyScreenToBitmap(LPRECT lpRect) <br />{ <br />//lpRect 代表选定区域 <br />{ <br />HDC hScrDC, hMemDC; <br />// 屏幕和内存设备描述表 <br />HBITMAP hBitmap, hOldBitmap; <br />// 位图句柄 <br />int nX, nY, nX2, nY2; <br />// 选定区域坐标 <br />int nWidth, nHeight; <br />// 位图宽度和高度 <br />int xScrn, yScrn; <br />// 屏幕分辨率 <br /><br />// 确保选定区域不为空矩形 <br />if (IsRectEmpty(lpRect)) <br />return NULL; <br />//为屏幕创建设备描述表 <br />hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL); <br />//为屏幕设备描述表创建兼容的内存设备描述表 <br />hMemDC = CreateCompatibleDC(hScrDC); <br />// 获得选定区域坐标 <br />nX = lpRect-&gt;left; <br />nY = lpRect-&gt;top; <br />nX2 = lpRect-&gt;right; <br />nY2 = lpRect-&gt;bottom; <br />// 获得屏幕分辨率 <br />xScrn = GetDeviceCaps(hScrDC, HORZRES); <br />yScrn = GetDeviceCaps(hScrDC, VERTRES); <br />//确保选定区域是可见的 <br />if (nX&lt;0) <br /><br />nX = 0; <br />if (nY&lt;0) <br />nY = 0; <br />if (nX2&gt;xScrn) <br />nX2 = xScrn; <br />if (nY2&gt;yScrn) <br />nY2 = yScrn; <br />nWidth = nX2 - nX; <br />nHeight = nY2 - nY; <br />// 创建一个与屏幕设备描述表兼容的位图 <br />hBitmap = CreateCompatibleBitmap <br />(hScrDC, nWidth, nHeight); <br />// 把新位图选到内存设备描述表中 <br />hOldBitmap =(HBITMAP)SelectObject(hMemDC, hBitmap); <br />// 把屏幕设备描述表拷贝到内存设备描述表中 <br />BitBlt(hMemDC, 0, 0, nWidth, nHeight, <br />hScrDC, nX, nY, SRCCOPY); <br />//得到屏幕位图的句柄 <br />hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); <br /><br />//清除 <br />DeleteDC(hScrDC); <br />DeleteDC(hMemDC); <br />// 返回位图句柄 <br />return hBitmap; <br />} <br />} <br /><br /><strong>二十、如何将位图缩放显示在Static控件中 <br /></strong>//在Staic控件内显示位图 <br />void CShowBmpInDlgDlg::ShowBmpInStaic() <br />{ <br />CBitmap hbmp; <br />HBITMAP hbitmap; <br />//将pStatic指向要显示的地方 <br />CStatic *pStaic; <br />pStaic=(CStatic*)GetDlgItem(IDC_IMAGE); <br />//装载资源 MM.bmp是我的一个文件名，用你的替换 <br />hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),"MM.bmp", <br />IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); <br /><br />hbmp.Attach(hbitmap); <br />//获取图片格式 <br />BITMAP bm; <br />hbmp.GetBitmap(&amp;bm); <br />CDC dcMem; <br />dcMem.CreateCompatibleDC(GetDC()); <br />CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp); <br />CRect lRect; <br />pStaic-&gt;GetClientRect(&amp;lRect); <br />//显示位图 <br />pStaic-&gt;GetDC()-&gt;StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Heigh <br />t(), <br />&amp;dcMem,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY); <br />dcMem.SelectObject(&amp;poldBitmap); <br />}<br /></font>
<img src ="http://www.cppblog.com/erran/aggbug/34185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:38 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：C++对象内存布局</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34184.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:37:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34184.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34184.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34184.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34184.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34184.html</trackback:ping><description><![CDATA[
		<br />引用：http://www.cppblog.com/stdyh/archive/2007/01/08/17442.html<br /><br />C++对象内存布局<br /><br /><br />
			写这个文章完全是因为想要搞清楚 vc 怎么布局每个 c++ 对象,以及怎样完成指针的转换的过程.<br />　　先问一个问题,两个不同类型的指针相互转换以后,他们在数值上是一样的吗?比如:<br /><br />　　　　<font color="#000066">int nValue = 10;<br />　　　　int *pInt = &amp;nValue;<br />　　　　void *pVoid = pInt;<br />　　　　char *pChar = (char*)pInt;</font><br /><br />　
　这些指针的值(不是说指针指向的内存的内容)是一样的吗? 如果你的回答是
yes,那如果是一个类的继承体系呢?在继承类向基类转换的过程中,指针的数值还是不变化的么?如果你的回答是"不一定会变化,要看类的体系是怎么设计的
"的话,那恭喜你,不用看下去了.如果你还不确定究竟变还是不变,究竟哪些变,哪些不变,究竟为什么要变为什么不变的话,接着看下来.<br /><br />　
　c++ 标准不规定 c++ 实现的时候的对象的具体的内存布局,除了在某些方面有小的限制以外,c++
对象在内存里面的布局完全是由编译器自行决定,这里我也只是讨论 vc++ .net 2003 build 7.1.3091
的实现方式,我并没有在 vc5 vc6 vc.net 2002 以及其他的 2003 build
上面做过测试,结论也许不适合那些编译平台.这些属于编译器具体实现,ms 保留有在不通知你我的情况下作出更改的权利.废话这么多,马上开始.<br /><br />　　对于 c 的内建指针的转换,结果是不用多讨论的,我们只是讨论 c++ 的对象.从最简单的开始.<br /><br />　　　　<font color="#000066">class CBase<br />　　　　{<br />　　　　public:<br />　　　　　　int m_nBaseValue;<br />　　　　};</font><br /><br />　　这样的一个类在内存里放置是非常简单的,他占有4个 bytes 的空间,不用多说,我们从他派生一个类出来.<br /><br />　　　　<font color="#000066">class CDerive1 : public CBase<br />　　　　{<br />　　　　public:<br />　　　　　　int m_nDerive1Value;<br />　　　　};</font><br /><br />　
　CDerive1 的对象在内存里面是怎么放的呢? 也很简单,占有8个 bytes 的空间,前4个 bytes 属于 CBase 类,后四个
bytes 属于自己.一个CDerive1 的指针转换成一个 CBase 的指针,结果是一样的.下面我们加上多重继承看看.<br /><br />　　　　<font color="#000066">class CFinal : public CDerive,public CBase <font color="#ff0000">// 这里的 CDerive 是一个和 CBase 差不多的基类</font><br />　　　　{<br />　　　　public:<br />　　　　　　int m_nFinalValue;<br />　　　　}; </font><br /><br />　
　CFinal 的对象在内存里面的布局稍微复杂一点,但是也很容易想象,他占有 12 个 bytes 的空间,前4个属于
CDerive,中间4个属于 CBase,后面4个才是自己的.那一个 CFinal 的指针转换成一个 CDerive 指针,数值会变么?
转换成一个 CBase 指针呢?又会变化么?答案是,前一个不变,后一个要变化,道理非常的明显,CFinal 对象的开头刚好是一个
CDerive 对象,而 CBase 对象却在 CFinal 对象的中间,自然是要变化的了,具体怎么变化呢? 加 4 就
ok(自然要检查是否是空指针).<br /><br />　　　　<font color="#ff0000">CBase *pBase = pFinal ? (CBase*)((char*)pFinal + sizeof(CDerive)) : 0;// 当你写下 pBase = pFinal 的时候,其实是这样的</font><br /><br />　　这种不带 virtual 的继承就这么简单,只是加上一个 offset 而已.下面我们看看如果加上 virtual function 的时候是什么样子的呢?<br />还是从简单类开始.<br /><br />　　　　<font color="#000066">class CBase<br />　　　　{<br />　　　　public:<br />　　　　　　virtual void VirtualBaseFunction(){}<br />　　　　　　int m_nBaseValue;<br />　　　　}; </font><br /><br />　
　这里刻意没有使用 virtual destructor,因为这个函数稍微有些不同.还是同样的问题,CBase 类在内存上占多大的空间?还是
4 bytes 么? 答案是 no, 在我的编译器上面是 8 bytes,多出来的 4 bytes 是 __vfptr(watch
窗口看见的名字),他是一个指针,指向了类的 vtable,那什么是 vtable 呢,他是用来干什么的呢? vtable 是用来支援
virtual function
机制的,他其实是一个函数指针数组(并不等同于c/c++语言里面的指针数组,因为他们的类型并不一定是一样的.)他的每一个元素都指向了一个你定义的
virtual
function,这样通过一个中间层来到达动态连编的效果,这些指针是在程序运行的时候准备妥当的,而不是在编译的时候准备妥当的,这个就是动态联编的
目的,具体是由谁来设置这些指针的呢?constructor/destructor/copy constructor/assignment
operator他们完成的,不用奇怪,编译器会在你写的这些函数里面安插些必要的代码用来设置 vtable
的值,如果你没有写这些函数,编译器会在适当的时候帮你生成这些函数.明白一点, vtable 是用来支持 virtual function
机制的,而需要 virtual 机制的类基本上都会由一个 __vfptr 指向他自己的 vtable.在调用 virtual
function的时候,编译器这样完成:<br /><br />　　　<font color="#000099">pBase-&gt;VirtualBaseFunction(); =&gt; pBase-&gt;__vfptr[0]();</font><font color="#ff0000">// 0 是你的virtual function 在 vtable 中的 slot number,编译器决定</font><br /><br />　
　现在应该很想象 CBase 的大小了吧,那这个 __vfptr 是放到什么位置的呢? 在 m_nBaseValue 之前还是之后呢?
在我的编译器上看来,是在之前,为什么要放到之前,是因为在通过 指向类成员函数的指针调用 virtual function
的时候能少些代码(指汇编代码),这个原因这里就不深入讨论了,有兴趣的同学可以看看 inside the c++ object model 一书.<br />　　接下来,我们加上继承来看看.<br /><br />　　　　<font color="#000099">class CDerive1 : public CBase<br />　　　　{<br />　　　　public:<br />　　　　　　virtual void VirtualDerive1Function();<br />　　　　};</font><br /><br />　
　这个时候你也许要说,内存布局跟没有 virtual 是一样的,只不过每个类多了一个 __vfptr
而已,呃...这个是不对的,在我的编译器上面 两个类共享同一个 __vfptr, vtable
里面放有两个指针,一个是两个类共享的,一个只属于 CDerive1 类,调用的时候如何呢?<br /><br />　　　<font color="#000099">pDerive1-&gt;VirtualDerive1Function() =&gt; pDerive1-&gt;__vfptr[1]();<br />　　　pDerive1-&gt;VirtualBaseFunction() =&gt; pDerive1-&gt;__vfptr[0]();</font><br /><br />　　至于指针的相互转换,数值还是没有变化的(也正是追求这种效果,所以把 __vfptr 放到类的开头,因为调整 this 指针也是要占有运行时的时间的).<br /><br />　
　现在加上多重继承瞧瞧,代码我不写上来了,就跟上面的 CFinal, CDerive, CBase
体系一样,只是每个类多一个VirtualxxxFunction出来,这个时候的指针调整还是没有什么变化,所以我们只是看看 vtable
的情况,你会说 CDerive 和 CFinal 共享一个 __vfptr,而 CBase 有一个自己的 __vfptr,而 CFinal 的
__vfptr 有 2 个slot,这个结论是正确的. 同时你也会说 通过 CFinal 类调用 CBase 的函数是要进行指针调整的,yes
you'r right,不仅仅是 this 指针调整(呃,this 指针会成为 function 的一个参数),还要调整 vtable 的值:<br /><br />　　　<font color="#0000cc">pFinal-&gt;VirtualBaseFunction() =&gt; (CBase*)((char*)pFinal + sizeof(CDerive))-&gt;__vfptr[0]();</font><br /><br />　　　转换成 asm 的代码大约是这样的:<br /><br /><font color="#000099">　　　mov eax,[pFinal] <font color="#ff00ff">; pFinal is a local object,pFinal will be epb - xx</font><br />　　　add eax,8 <font color="#ff00ff">; 8 = sizeof(CDerive)</font><br />　　　mov ecx,eax <font color="#ff00ff">; ecx is this pointer</font><br />　　　mov edx,[eax] <font color="#ff00ff">; edx = vtable address</font><br />　　　call [edx] <font color="#ff00ff">; call vtable[0]</font></font><br /><br />　　写到这里也就明白this指针是怎么调整的.带 virtual function 的继承也不复杂,this指针调整也是很简单的,下面看最复杂的部分 virtual inheritance.<br /><br />　
　我的编译器支持虚拟继承的方式和虚函数的方式差不多,都是通过一个 table 完成,只是这个就看不到 vc 赋予的名字了,我们叫他
vbtable 吧,编译器同样在类里面加入一个指向 vbtable 的指针,我们叫他 __vbptr 吧,这个指针指向了 vbtable ,而
vbtable 里面的每一项对应了一个基类,vbtable
记录了每个基类的某一个偏移量,通过这个偏移量就能计算出具体类的指针的位置.看个简单的例子:<br /><br />　　　<font color="#000099">class CBase<br />　　　{<br />　　　public:<br />　　　　　virtual ~CBase(){}<br />　　　}; <br /><br />　　　class CMid1 : public virtual CBase<br />　　　{<br />　　　public:<br />　　　　　virtual ~CMid1(){}<br />　　　　　int m_nMid1;<br />　　　}; <br /><br />　　　class CMid2 : public virtual CBase<br />　　　{<br />　　　public:<br />　　　　　virtual ~CMid2(){}<br />　　　　　int m_nMid2;<br />　　　}; <br /><br />　　　class CFinal : public CMid1,public CMid2<br />　　　{<br />　　　public:<br />　　　　　virtual ~CFinal(){}<br />　　　　　int m_nFinal;<br />　　　}; <br /><br />　　　CFinal final;<br />　　　CFinal *pFinal = &amp;final;    <font color="#ff00ff">// pFinal = 0x0012feb4;</font><br />　　　CBase *pBase = pFinal; <font color="#ff00ff">// pBase = 0x0012fec8 = pFinal + 0x14;</font><br />　　　CMid1 *pMid1 = pFinal; <font color="#ff00ff">// pMid1 = 0x0012feb4 = pFinal;</font><br />　　　CMid2 *pMid2 = pFinal; <font color="#ff00ff">// pMid2 = 0x004210b4 = pFinal;</font></font><br /><br />　
　结果让你吃惊吗? 最奇怪的地方居然是 CMid2 和 CMid1 的地址居然是一样的,这个是因为 vc 把 vbtable 放到了
CFinal 类的开头的原因,而CMid1 和 CMid2 也同样要使用这个 vbtable, 所以 这个三个的地址也就必须相同了.那
CBase 的地址是怎么出来的呢? 呃...刚刚我们说了 vbtable 放到了CFinal 的开头(vc
一定会放在开头吗?答案是不一定,这个稍后解释).在我的机器上面 final 对应内存的第一个 dword 是
0x00426030,查看这个地址,第一个dword 是 0 ,第二个就是 0x14,刚好和 pBase
的偏移相同,这个只是巧合,也许你换个类的继承体系就完全不同了,但是我只是想说明一点,基类的偏移计算是和 vbtable
的值相关联的.下面我们就来看看 vc 是怎么计算这些偏移的.<br />　　vc 在分析我们的代码的时候,生成了一份类的继承体系信息,其中有一个叫 thisDisplacement 的_PMD结构:<br /><br />　　　　<font color="#000099">struct _PMD <font color="#ff00ff">// total undocumented</font><br />　　　　{<br />　　　　　　int mdisp; <font color="#ff00ff">// i think the meaning is Multiinheritance DISPlacement</font><br />　　　　　　int pdisp; <font color="#ff00ff">// Pointer to vbtable DISPlacement</font><br />　　　　　　int vdisp; <font color="#ff00ff">// Vbtable DISPlacement</font><br />　　　　}; </font><br /><br />　
　结构的名字和成员变量的名字确确实实是 vc 的名字(在 watch 窗口输入 (_PMD*)0
就能看到这个结构的详细信息),每个字段的含义却是我自己猜测出来的.mdisp 大概用来表示多重继承(包括单一继承)的时候的偏移量,pdisp
表示 vbtable 的偏移量,而 vdisp 表示类在 vbtable
里面的下标.那么有了这个结构怎样才能完成指针的转换呢?假如我们有一个派生类指针
pFinal,要转换成一个特定的基础类,我们首先要知道和这个基类对应的 _PMD
结构的信息(这个信息的获取,我暂时没有找到一个非常方便的方法,现在我使用的方法下面会有描述),有了这个信息以后,转换就方便了.首先找到
vbtabel 的地址 *(pFinal + pdisp),然后找到基类的偏移 *(*(pFinal + pdisp) + vdisp)
这个偏移值是相对vbtable的,所以还要加上 vbtable的偏移,最后加上 mdisp的偏移,如下:<br /><br />　　<font color="#000099">char *pFinal = xxx; <font color="#ff00ff">// need a init value</font><br />　　char *pBase; <font color="#ff00ff">// we must calc</font><br />　　pBase = pFinal + mdisp + *(int *)(*(int *)(pFinal + pdisp) + vdisp) + pdisp;</font><br /><br />　　<font color="#ff0000">注意: 当 pdisp &lt; 0 的时候就表示这个类没有 vbtable 直接使用 pFinal + mdisp 就得到结果了.<br />　　<font color="#00ff00">所以这个结构是一个通用的结构,专门用作类型转换,不管是有无虚继承都能使用这个结构进行类型转换.</font></font><br />　　通过这个结构,我们也能看到 vc 是怎样布局这个 object 的.<br /><br />　　看到这里,也许你要大呼一口气,妈妈呀,一个类型转换要这么的麻烦吗?我直接写 pBase = pFinal 不就可以了吗? 恭喜你还没有被我忽悠得晕头转向,哈哈.其实你写下那行语句的时候,编译器在帮你做这个转换,大约生成下面的代码<br /><br />　　　　<font color="#000099">mov eax,[pFinal] <font color="#ff00ff">;final address</font><br />　　　　mov ecx,[eax] <font color="#ff00ff">; vbtable address *(int *)(pFinal + pdisp)</font><br />　　　　mov edx,eax <font color="#ff00ff">; save to edx</font><br />　　　　add edx,[ecx + 4] <font color="#ff00ff">; ecx + 4 is (*(int *)(pFinal + pdisp) + vdisp)</font><br />　　　　mov [pBase],edx <font color="#ff00ff">; edx = pFinal + mdisp + *(int *)(*(int *)(pFinal + pdisp) + vdisp) + pdisp;</font><br />　　　　<font color="#ff00ff">; here mdisp = 0, pdisp = 0, vdisp = 4</font></font><br /><br />　
　也许你要说了,我要这些东西来干什么?要转换的时候直接转换就好了,编译器会帮做,的确,大多数的时候确实是这样,但是,在某些时候却并不如此,现在你
要实现一个功能,输入一个指针,输入一个 _PMD 结构,你要实现一个AdjustPointer
的函数来生成另一个指针.这个时候你也只能这样完成了,因为我没有给你两个指针的名字,就算给了你字符串形式的名字也没有用,呃....你也许会说,办法
是有的,的确是有,模板就能实现这种功能,呵..这个我们暂时不讨论具体的实现细节.也许你要问了,究竟什么时候会去实现这种听都没有听过的功能,其实这
个函数是真正存在的,只不过不是由你来实现的,而是 ms 的人实现的,你只用写一个 带有 c++ 异常的程序,使用 ida
反汇编,然后查找函数,就能找到这个函数了,他用来在异常处理时创建 catch 所需要的
object.至于这个详细的信息,请期待.我会最快速度写出关于 vc 是怎样实现 c++ 异常的文章来.<br /><br />　　最后了,说说那个
_PMD 结构的获取方式.看的时候不要吃惊,方法比较的麻烦,比如我想知道和 CFinal 类相关的 _PMD 信息,先新建工作,写下
throw pFinal 这样的语句,编译,在这个语句的地方设置断点,运行,转到反汇编,进入 __CxxThrowException@8
函数,这个时候不出意外你能看到一个叫 pThrowInfo 的东西(如果看不到,请打开"显示符号名"选项),在 watch
窗口里面输入pThrowInfo,展开他,看到一个pCatchableTypeArray,记录下他的
nCacthableTypes的值,然后在 watch 里面输入<br />pThrowInfo-&gt;pCatchableTypeArray-&gt;arrayOfCatchableTypes[0]
到 pThrowInfo-&gt;pCatchableTypeArray-&gt;arrayOfCatchableTypes[n], n
就是你刚刚记录的值减1,再展开他们,你就能看到一个 thisDisplacement 的数据,继续展开就是 mdisp
等等了,很是麻烦吧.哈..你已经猜到了,这个是和异常有关系的.<br /><br />　　后记:
这段时间,我一直在读些反汇编之后的代码,也颇有些心得,所以才有想法写一些文章,探讨 vc
编译器鲜为人知(太过狂妄了)的秘密,这个方面的文章也有人写过,那些文章也给我不少的启发,我不认为自己是第一个发现这些秘密的人,但是至少我自己知道
的,我是第一个把这些东西写出来的人.文章里面作墨多的部分都是自己发现的.就这个文章里面的内容来说,inside the c++ object
model 是有比较详细的描写,但是他并不是转换针对 vc 这个编译器的实现,而 _PMD 这个结构我也没有在什么地方见有人描述过,只是在
windows develop network
的2002年12月的杂志上看有人提到过这个结构,可惜他却没有了解(至少他在他发表文章的时候是如是说的)这个结构的用处(正是因为这个原因,我才有写
这个文章以及后续文章的冲动).所以,这个文章也算是我自己的原创吧.这个文件虽然和游戏制造没有太大的关系,但是小 T
自视清高,不愿意自己的文章被一帮不懂的人评价来评价去的,所以也没有发到那些著名的 xxx 网站,只发 goldpoint.转载请注明出处(小 T 对自己的第一个原创文章比较珍惜,比较重视,谢谢).<br /><br /><br /><img src ="http://www.cppblog.com/erran/aggbug/34184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:37 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：关于调用约定(cdecl、fastcall、、thiscall) 的一点知识</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34182.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:33:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34182.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34182.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34182.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34182.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<div class="tit">引用：http://www.cppblog.com/oosky/archive/2007/01/08/17422.html<br /><br />函数调用规范<br /><br /><div class="cnt"><p align="left">当高级语言函数被编译成机器码时，有一个问题就必须解决：因为CPU没有办法知道一个函数调用需要多少个、什么样的参数。即计算机不知道怎么给这个函数传递参数，<font color="#0000ff">传递参数的工作必须由函数调用者和函数本身来协调</font>。为此，计算机提供了一种被称为栈的数据结构来支持参数传递。 </p><p align="left">   函数调用时，调用者依次把参数压栈，然后调用函数，函数被调用以后，在堆栈中取得数据，并进行计算。函数计算结束以后，或者调用者、或者函数本身修改堆栈，使堆栈恢复原装。在参数传递中，有两个很重要的问题必须得到明确说明：</p><p align="left">
            																  1) 当参数个数多于一个时，按照什么顺序把参数压入堆栈；<br />2) 函数调用后，由谁来把堆栈恢复原装。<br /><font color="#0000ff" size="2">3）函数的返回值放在什么地方</font></p>在高级语言中，通过函数<font color="#0000ff">调用规范(Calling Conventions)</font>来说明这两个问题。常见的调用规范有： 
            <div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font color="#800080">stdcall</font><br /><font color="#800080">cdecl<br /></font><font color="#800080">fastcall<br /></font><font color="#800080">thiscall<br /></font><font color="#800080">naked call</font></pre></div><h2 align="left"><font size="4">stdcall调用规范</font></h2><p align="left">stdcall
很多时候被称为pascal调用规范，因为pascal是早期很常见的一种教学用计算机程序设计语言，其语法严谨，使用的函数调用约定是stdcall。
在Microsoft C++系列的C/C++编译器中，常常用PASCAL宏来声明这个调用约定，类似的宏还有WINAPI和CALLBACK。 </p><p align="left">stdcall调用规范声明的语法为：</p><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"><font color="#0000ff">int</font> __stdcall function(<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b)</font><br /></pre></div><div align="left">stdcall的调用约定意味着： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: medium; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"> 1）参数从右向左压入堆栈；<br /> 2）函数自身修改堆栈；<br /> 3) 函数名自动加前导的下划线，后面紧跟一个@符号，其后紧跟着参数的尺寸。</font><br /></pre></div><div align="left">以上述这个函数为例，参数b首先被压栈，然后是参数a，函数调用function(1,2)调用处翻译成汇编语言将变成： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">  push 2          第二个参数入栈<br />              push 1          第一个参数入栈<br />              call function   调用参数，注意此时自动把cs:eip入栈</font></pre></div><div align="left">而对于函数自身，则可以翻译为： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">      push  ebp               保存ebp寄存器，该寄存器将用来保存堆栈的栈顶指针，可以在函数退出时恢复<br />              mov   ebp,esp           保存堆栈指针<br />              mov   eax,[ebp + 8H]    堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向a<br />              add   eax,[ebp + 0CH]   堆栈中ebp + 12处保存了b<br />              mov   esp,ebp           恢复esp<br />              pop   ebp<br />              ret   8</font></pre></div><p align="left">而在编译时，这个函数的名字被翻译成_function@8 </p><p align="left">注意不同编译器会插入自己的汇编代码以提供编译的通用性，但是大体代码如此。其中在函数开始处保留esp到ebp中，在函数结束恢复是编译器常用的方法。 </p><p align="left">从函数调用看，2和1依次被push进堆栈，而在函数中又通过相对于ebp(即刚进函数时的堆栈指针）的偏移量存取参数。函数结束后，ret 8表示清理8个字节的堆栈，函数自己恢复了堆栈。 </p><h2 align="left"> <font size="4">cdecl调用规范</font></h2><p align="left">cdecl调用约定又称为C调用约定，是C语言缺省的调用约定，它的定义语法是： </p><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"><font color="#0000ff">              int</font> function (<font color="#0000ff">int</font> a ,<font color="#0000ff">int</font> b)           <font color="#ff0000">// 不加修饰就是C调用约定</font><br />              <font color="#0000ff">int</font> __cdecl function(<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b)     <font color="#ff0000">// 明确指出C调用约定</font></font></pre></div><p align="left"> 
cdecl调用约定的参数压栈顺序是和stdcall是一样的，参数首先由有向左压入堆栈。所不同的是，函数本身不清理堆栈，调用者负责清理堆栈。由于这
种变化，C调用约定允许函数的参数的个数是不固定的，这也是C语言的一大特色。对于前面的function函数，使用cdecl后的汇编码变成： </p><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">调用处<br />              push   1<br />              push   2<br />              call   function<br />              add    esp,8              注意：这里调用者在恢复堆栈<br />              被调用函数_function处<br />              push   ebp                保存ebp寄存器，该寄存器将用来保存堆栈的栈顶指针，可以在函数退出时恢复<br />              mov    ebp,esp            保存堆栈指针<br />              mov    eax,[ebp + 8H]     堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向a<br />              add    eax,[ebp + 0CH]    堆栈中ebp + 12处保存了b<br />              mov    esp,ebp            恢复esp<br />              pop    ebp<br />              ret                       注意，这里没有修改堆栈</font></pre></div><p align="left">MSDN中说，该修饰自动在函数名前加前导的下划线，因此函数名在符号表中被记录为_function。 <br /></p><p align="left">由于参数按照从右向左顺序压栈，因此最开始的参数在最接近栈顶的位置，因此当采用不定个数参数时，第一个参数在栈中的位置肯定能知道，只要不定的参数个数能够根据第一个后者后续的明确的参数确定下来，就可以使用不定参数，例如对于sprintf函数，定义为：</p><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"><font color="#0000ff">int</font> sprintf(<font color="#0000ff">char</font>* buffer,<font color="#0000ff">const</font><font color="#0000ff">char</font>* format,...)</font></pre></div><div align="left">由于所有的不定参数都可以通过format确定，因此使用不定个数的参数是没有问题的。 </div><h2 align="left"> <font size="4">fastcall调用规范</font></h2><div align="left">fastcall调用约定和stdcall类似，它意味着： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: medium; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">            1) 函数的第一个和第二个DWORD参数（或者尺寸更小的）通过ecx和edx传递，其他参数通过从右向左的顺序压栈；<br />            2) 被调用函数清理堆栈；<br />            3) 函数名修改规则同stdcall。</font></pre></div><div align="left">其声明语法为：int __fastcall function(int a,int b) </div><h2 align="left"> <font size="4">thiscall调用规范</font></h2><p align="left">thiscall是唯一一个不能明确指明的函数修饰，因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针，因此必须特殊处理，thiscall意味着： </p><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: medium; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">            1) 参数从右向左入栈；<br />            2) 如果参数个数确定，this指针通过ecx传递给被调用者；如果参数个数不确定，this指针在所有参数压栈后被压入堆栈；<br />            3) 对参数个数不定的，调用者清理堆栈，否则函数自己清理堆栈。</font></pre></div><div align="left">为了说明这个调用约定，定义如下类和使用代码： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"><br /><font color="#0000ff">class</font> A<br />            {<br /><font color="#804040">public</font>:<br /><font color="#0000ff">int</font> function1(<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b);<br /><font color="#0000ff">int</font> function2(<font color="#0000ff">int</font> a,...);<br />            };<br /><font color="#0000ff">int</font> A::function1 (<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b)<br />            {<br /><font color="#804040">return</font> a+b;<br />            }<br /><font color="#0000ff">int</font> A::function2(<font color="#0000ff">int</font> a,...)<br />            {<br /><font color="#0000ff">va_list</font> ap;<br />            va_start(ap,a);<br /><font color="#0000ff">int</font> i;<br /><font color="#0000ff">int</font> result = <font color="#ff00ff">0</font>;<br /><font color="#804040">for</font>(i = <font color="#ff00ff">0</font> ; i &lt; a ; i ++)<br />            {<br />            result += va_arg(ap,<font color="#0000ff">int</font>);<br />            }<br /><font color="#804040">return</font> result;<br />            }<br /><font color="#0000ff">void</font> callee()<br />            {<br />            A a;<br />            a.function1(<font color="#ff00ff">1</font>,<font color="#ff00ff">2</font>);<br />            a.function2(<font color="#ff00ff">3</font>,<font color="#ff00ff">1</font>,<font color="#ff00ff">2</font>,<font color="#ff00ff">3</font>);<br />            }</font></pre></div><div align="left">callee函数被翻译成汇编后就变成： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">// 函数function1调用<br />              0401C1D    push        2<br />              00401C1F   push        1<br />              00401C21   lea         ecx,[ebp-8]<br />              00401C24   call   function1             注意，这里this没有被入栈<br />              // 函数function2调用<br />              00401C29   push        3<br />              00401C2B   push        2<br />              00401C2D   push        1<br />              00401C2F   push        3<br />              00401C31   lea         eax,[ebp-8]      这里引入this指针<br />              00401C34   push        eax<br />              00401C35   call   function2<br />              00401C3A   add         esp,14h</font></pre></div><div align="left"><font size="2">可见，对于参数个数固定情况下，它类似于stdcall，不定时则类似cdecl</font></div><h2 align="left"> <font size="4">naked call调用规范</font></h2><div align="left">这是一个很少见的调用约定，一般程序设计者建议不要使用。编译器不会给这种函数增加初始化和清理代码，更特殊的是，不能用return返回返回值，只能用插入汇编返回结果。这一般用于实模式驱动程序设计，假设定义一个求和的加法程序，可以定义为： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"> __declspec(naked) <font color="#0000ff">int</font>  add(<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b)<br />               {<br />                   __asm mov eax,a<br />                   __asm add eax,b<br />                   __asm ret<br />               }</font></pre></div><div align="left">注意，这个函数没有显式的return返回值，返回通过修改eax寄存器实现，而且连退出函数的ret指令都必须显式插入。上面代码被翻译成汇编以后变成： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;">  <font size="2"> mov    eax,[ebp+8]<br />   add    eax,[ebp+12]<br />   ret    8</font></pre></div><div align="left">注意这个修饰是和__stdcall及cdecl结合使用的，前面是它和cdecl结合使用的代码，对于和stdcall结合的代码，则变成： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2"> __declspec(naked) <font color="#0000ff">int</font> __stdcall function(<font color="#0000ff">int</font> a,<font color="#0000ff">int</font> b)<br />               {<br />                   __asm mov eax,a<br />                   __asm add eax,b<br />                   __asm ret <font color="#ff00ff">8</font><font color="#ff0000">//注意后面的8</font><br />               }</font></pre></div><div align="left">至于这种函数被调用，则和普通的cdecl及stdcall调用函数一致。 </div><h2 align="left"> <font size="4">函数调用约定导致的常见问题</font></h2><div align="left">如果定义的约定和使用的约定不一致，则将导致堆栈被破坏，导致严重问题，下面是两种常见的问题： </div><div align="left"><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0% 50%; font-size: medium; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: -Lucida Sans Typewriter-;"><font size="2">1) 函数原型声明和函数体定义不一致<br />            2) DLL导入函数时声明了不同的函数约定</font></pre></div></div></div>
		</div>
		<br />
		<br />
<img src ="http://www.cppblog.com/erran/aggbug/34182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:33 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Microsoft's HTML Help (.chm) format</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34180.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:21:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34180.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34180.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34180.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34180.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Microsoft's HTML Help (.chm) format																				Preface																				This is documentation on the .chm format used by Microsoft HTMLHelp. This format has been reverse engine...&nbsp;&nbsp;<a href='http://www.cppblog.com/erran/archive/2007/10/14/34180.html'>阅读全文</a><img src ="http://www.cppblog.com/erran/aggbug/34180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:21 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：C++资源之不完全导引（完整版）</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34178.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:14:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34178.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34178.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34178.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34178.html</trackback:ping><description><![CDATA[
		<br />
		<table class="fixedTable blogpost" border="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="ellipse">
										<span class="bvTitle" id="subjcns!1p5qP-LmQlonNx_ujZCY3OgA!128">
												<strong>
														<font size="3">C++资源之不完全导引（完整版）</font>
												</strong>
										</span>
								</td>
						</tr>
						<tr>
								<td class="bvh8">
										<strong>
												<font size="3">
												</font>
										</strong>
										<br />
								</td>
						</tr>
						<tr>
								<td id="msgcns!1p5qP-LmQlonNx_ujZCY3OgA!128">
										<p>C++资源之不完全导引（完整版）</p>
										<p>来源：<a href="http://www.csdn.net/"><u><font color="#0000ff">www.csdn.net</font></u></a></p>
										<p>撰文：曾毅、陶文</p>
										<p>声明：本文2004年5月首发于《CSDN开发高手》，版权归该杂志与《程序员》杂志社<br />所有。</p>
										<p>------------------------------------------------------------------------<br />--------</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　1，前言</p>
		<p>　　无数次听到“我要开始学习C++!”的呐喊，无数次听到“C++太复杂了，我真的<br />学不会”的无奈。Stan Lippman先生曾在《C++ Primer》一书中指出“C++是最为难<br />学的高级程序设计语言之一”，人们常将“之一”去掉以表达自己对C++的敬畏。诚<br />然，C++程序设计语言对于学习者的确有很多难以逾越的鸿沟，体系结构的庞大，应<br />接不暇并不断扩充的特性……除此之外，参考资料之多与冗杂使它的学习者望而却<br />步，欲求深入者苦不堪言。希望这一份不完全导引能够成为您C++学习之路上的引路<br />灯。</p>
		<p>　　撰写本文的初衷并不打算带领大家体验古老的C++历史，如果你想了解C++的历<br />史与其前期发展中诸多技术的演变，你应当去参考Bjarne的《The Design and Evo<br />lution of C++》。当然也不打算给大家一个无所不包的宝典（并非不想：其一是因<br />水平有限，其二无奈C++之博大精深），所给出的仅仅是一些我们认为对于想学习C<br />++的广大读者来说最重要并且触手可及的开发与学习资源。</p>
		<p>　　本文介绍并分析了一些编译器，开发环境，库，少量的书籍以及参考网站，并<br />且尽可能尝试着给出一个利用这些资源的导引，望对如同我们一样的初学者能够有<br />所裨益。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　2，编译器</p>
		<p>　　在C++之外的任何语言中，编译器都从来没有受到过如此之重视。因为C++是一<br />门相当复杂的语言，所以编译器也难于构建。直到最近我们才开始能够使用上完全<br />符合C++标准的编译器（哦，你可能会责怪那些编译器厂商不能尽早的提供符合标准<br />的编译器，这只能怪他们各自维系着自身的一套别人不愿接受的标准）。什么？你<br />说这无关紧要？哦，不，你所需要的是和标准化C++高度兼容的编译环境。长远来看<br />，只有这样的编译器对C++开发人员来说才是最有意义的工具，尤其是对于程序设计<br />语言的学习者。一至性让代码具备可移植性，并让一门语言及其库的应用更为广泛<br />。嗯，是的，我们这里只打算介绍一些公认的优秀编译器。</p>
		<p>　　2.1 Borland C++</p>
		<p>　　这个是Borland C++ Builder和Borland C++ Builder X这两种开发环境的后台<br />编译器。（哦，我之所以将之分为两种开发环境你应当能明白为什么，正如Delphi<br />7到Delphi8的转变，是革命性的两代。）Borland C++由老牌开发工具厂商Borland<br />倾力打造。该公司的编译器素以速度快，空间效率高著称，Borland C++ 系列编译<br />器秉承了这个传统，属于非常优质的编译器。标准化方面早在5.5版本的编译器中对<br />标准化C++的兼容就达到了92.73%。目前最新版本是Borland C++ Builder X中的6.<br />0版本，官方称100%符合ANSI/ISO的C++标准以及C99标准。嗯…这正是我前面所指的<br />“完全符合C++标准的编译器”。</p>
		<p>　　2.2 Visual C++</p>
		<p>　　这个正是我们熟知的Visual Studio 和 Visual Studio.net 2002, 2003以及2<br />005 Whidbey中带的C++编译器。由Microsoft公司研制。在Visual Studio 6.0中，<br />因为编译器有太多地方不能与后来出现的C++标准相吻合而饱受批评（想想你在使用<br />STL的时候编译时报出的那些令人厌恶的error和warning吧）。VC++6.0对标准化C+<br />+的兼容只有83.43%。但是随着C++编译器设计大师Stanley Lippman以及诸多C++社<br />群达人的加盟，在Visual Studio.NET 2003中，Visual C++编译器已经成为一个非<br />常成熟可靠的C++编译器了。Dr.Dobb's Journal的评测显示Visual C++7.1对标准C<br />++的兼容性高达98.22%，一度成为CBX之前兼容性最好的编译器。结合强大的Visua<br />l Studio.NET开发环境，是一个非常不错的选择。至于Whidbey时代的Visual C++,<br />似乎微软所最关注的是C++/CLI……我们不想评论微软下一代的C++编译器对标准化<br />兼容如何，但他确实越来越适合.NET (其实你和我的感觉可能是一样的，微软不应<br />当把标准C++这块肥肉丢给Borland,然而微软可能并不这样认为)。</p>
		<p>　　2.3 GNU C++</p>
		<p>　　著名的开源C++编译器。是类Unix操作系统下编写C++程序的首选。特点是有非<br />常好的移植性，你可以在非常广泛的平台上使用它，同时也是编写跨平台，嵌入式<br />程序很好的选择。另外在符合标准这个方面一直都非常好，GCC3.3大概能够达到96<br />.15%。但是由于其跨平台的特性，在代码尺寸速度等优化上略微差一点。</p>
		<p>　　基于GNU C++的编译器有很多，比如：</p>
		<p>　　(1) Mingw</p>
		<p>　　<a href="http://www.mingw.org/"><u><font color="#0000ff">http://www.mingw.org/</font></u></a></p>
		<p>　　GCC的一个Windows的移植版本（Dev-C++的后台）</p>
		<p>　　(2) Cygwin</p>
		<p>　　<a href="http://sources.redhat.com/cygwin/"><u><font color="#0000ff">http://sources.redhat.com/cygwin/</font></u></a></p>
		<p>　　GCC的另外一个Windows移植版本是Cygwin的一部分，Cygwin是Windows下的一个<br />Unix仿真环境。严格的说是模拟GNU的环境，这也就是"Gnu's Not Unix"要表达的意<br />思，噢，扯远了，这并不是我们在这里关心的实质内容。</p>
		<p>　　(3) Djgpp</p>
		<p>　　<a href="http://www.delorie.com/djgpp/"><u><font color="#0000ff">http://www.delorie.com/djgpp/</font></u></a></p>
		<p>　　这是GCC的DOS移植版本。</p>
		<p>　　(4) RSXNT</p>
		<p>　　<a href="http://www.mathematik.uni-bielefeld.de/%7Erainer/"><u><font color="#0000ff">http://www.mathematik.uni-bielefeld.de/~rainer/</font></u></a></p>
		<p>　　这是GCC的DOS和Windows移植版本。</p>
		<p>　　(5) Intel C++</p>
		<p>　　著名CPU制造厂商Intel出品的编译器，Special Design for Intel x86！对于<br />Intel x86结构的CPU经过特别的优化。在有些应用情况下，特别是数值计算等高性<br />能应用，仅仅采用Intel的编译器编译就能大幅度的提高性能。</p>
		<p>　　(6) Digital Mars C++</p>
		<p>　　网络上提供免费下载，Zortech/Symantec C++的继承者，其前身在当年惨烈的<br />C++四国战中也是主角之一。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　3，开发环境</p>
		<p>　　开发环境对于程序员的作用不言而喻。选择自己朝夕相处的环境也不是容易的<br />事情，特别是在IDE如此丰富的情况下。下面就是我们推荐的一些常见的C++开发环<br />境，并没有包括一些小型的，罕见的IDE。其中任何一款都是功能丰富，可以用作日<br />常开发使用的。对于不同层面的开发者，请参见内文关于适用对象的描述。</p>
		<p>　　3.1 Visual Studio 6.0</p>
		<p>　　这个虽然是Microsoft公司的老版本的开发环境，但是鉴于其后继版本Visual<br />Studio.NET的庞大身躯，以及初学者并不那么高的功能要求，所以推荐这个开发环<br />境给C++的初学者，供其学习C++的最基本的部分，比如C的那部分子集，当然你别指<br />望他能够支持最新的C99标准。在日常的开发中，仍然有很多公司使用这个经典稳定<br />的环境，比如笔者就看曾亲见有些公司将其编译器替换为GCC做手机开发之用。</p>
		<p>　　3.2 Visual Studio.NET 2003</p>
		<p>　　作为Microsoft公司官方正式发布的最新版本开发环境，其中有太多激动人心的<br />功能。结合其最新的C++编译器。对于机器配置比较好的开发人员来说，使用这个开<br />发环境将能满足其大部分的要求。这里不打算单独说Visual Studio Whidbey,虽然<br />Visual Studio .NET 2005 - Whidbey社区预览版已经推出，但暂不是很稳定，读者<br />可以亲身去体验。</p>
		<p>　　3.3 Borland C++ Builder 6</p>
		<p>　　这个并不是Borland的C++开发环境的最新版本。选择它的原因是它不是用Java<br />写的IDE，速度比较快。它有一个很完善的GUI窗体设计器，和Delphi共用一个VCL。<br />由于这些特点，比较适合初学者上手。但是由于其GUI的中心位置，可能不利于对于<br />C++语言的学习。而且其为了支持VCL这个Object Pascal写的库也对C++进行了一些<br />私有的扩充。使得人们有一个不得不接受的事实：“Borland C++ Builder 6的高手<br />几乎都是Delphi高手”。</p>
		<p>　　3.4 Borland C++ Builder X</p>
		<p>　　正如前文所述，虽然版本号上和前面那个IDE非常相象，但是其实它们是完全不<br />同的两个集成开发环境。C++Builder更多的是一个和Delphi同步的C++版本的开发环<br />境，C++BuilderX则是完全从C++的角度思考得出的一个功能丰富的IDE。其最大的特<br />点是跨平台，跨编译器，多种Framework的集成，并且有一个WxWindows为基础的GU<br />I设计器。尤其是采用了纯C++来重写了整个Framework,摒弃了以前令人无奈的版本<br />。对于C++的开发来说，从编译器，到库，到功能集成都是非常理想的。可以预见，<br />Borland C++ Builder X 2.0很值得C++爱好者期待。唯一令人难堪之处是作为一个<br />C++的开发工具，其IDE是用Java写的，在配置不够理想的机器上请慎重考虑再安装<br />。</p>
		<p>　　3.5 Emacs + GCC</p>
		<p>　　前面讲的大部分是Windows环境下的集成开发环境。Linux上的开发者更倾向于<br />使用Emacs来编辑C++的文件，用Makefile来命令GCC做编译。虽然看上去比较松散，<br />但是这些东西综合起来还是一个开0发环境。如果你能够娴熟的使用这样的环境写程<br />序，你的水平应该足够指导我们来写这篇陋文了。</p>
		<p>　　3.6 Dev C++</p>
		<p>　　GCC是一个很好的编译器。在Windows上的C++编译器一直和标准有着一段距离的<br />时候，GCC就是一个让Windows下开发者流口水的编译器。Dev-C++就是能够让GCC跑<br />在Windows下的工具，作为集成开发环境，还提供了同专业IDE相媲美的语法高亮，<br />代码提示，调试等功能。由于使用Delphi开发，占用内存少，速度很快，比较适合<br />轻量级的学习和使用。</p>
		<p>　　3.7 Eclipse + CDT</p>
		<p>　　Eclipse可是近来大名鼎鼎的开发工具。最新一期的Jolt大奖就颁给了这个杰出<br />的神物。说其神奇是因为，它本身是用Java写的，但是拥有比一般Java写的程序快<br />得多的速度。而且因为其基于插件组装一切的原则，使得能够有CDT这样的插件把E<br />clipse变成一个C/C++的开发环境。如果你一直用Eclipse写Java的程序，不妨用它<br />体验一下C++开发的乐趣。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　4，工具</p>
		<p>　　C++的辅助工具繁多，我们分门别类的为大家作介绍：</p>
		<p>　　4.1 文档类</p>
		<p>　　(1) Doxygen</p>
		<p>　　参考站点：<a href="http://www.doxygen.org/"><u><font color="#0000ff">http://www.doxygen.org</font></u></a></p>
		<p>　　Doxygen是一种适合C风格语言（如C++、C、IDL、Java甚至包括C#和PHP）的、<br />开放源码的、基于命令行的文档产生器。</p>
		<p>　　(2) C++2HTML</p>
		<p>　　参考站点：<a href="http://www.bedaux.net/cpp2html/"><u><font color="#0000ff">http://www.bedaux.net/cpp2html/</font></u></a></p>
		<p>　　把C++代码变成语法高亮的HTML</p>
		<p>　　(3) CodeColorizer</p>
		<p>　　参考站点：<a href="http://www.chami.com/colorizer/"><u><font color="#0000ff">http://www.chami.com/colorizer/</font></u></a></p>
		<p>　　它能把好几种语言的源代码着色为HTML</p>
		<p>　　(4) Doc-O-Matic</p>
		<p>　　参考站点：<a href="http://www.doc-o-matic.com/"><u><font color="#0000ff">http://www.doc-o-matic.com/</font></u></a></p>
		<p>　　Doc-O_Matic为你的C/C++，C++.net，Delphi/Pascal, VB.NET，C#和Java程序<br />或者组件产生准确的文档。Doc-O-Matic使用源代码中的符号和注释以及外部的文档<br />文件创建与流行的文档样式一致的文档。</p>
		<p>　　(5) DocVizor</p>
		<p>　　参考站点：<a href="http://www.ucancode.net/Products/DocBuilder/Features.htm"><u><font color="#0000ff">http://www.ucancode.net/Products/DocBuilder/Features.htm</font></u></a></p>
		<p>　　DocVizor满足了面向对象软件开发者的基本要求——它让我们能够看到C++工程<br />中的类层次结构。DocVizor快速地产生完整可供打印的类层次结构图，包括从第三<br />方库中来的那些类，除此之外DocVizor还能从类信息中产生HTML文件。</p>
		<p>　　(6) SourcePublisher C++</p>
		<p>　　参考站点：<a href="http://www.scitools.com/sourcepublisher_c.html"><u><font color="#0000ff">http://www.scitools.com/sourcepublisher_c.html</font></u></a></p>
		<p>　　给源代码产生提供快速直观的HTML报表，包括代码，类层次结构，调用和被调<br />用树，包含和被包含树。支持多种操作系统。</p>
		<p>　　(7) Understand</p>
		<p>　　参考站点：<a href="http://www.scitools.com/ucpp.html"><u><font color="#0000ff">http://www.scitools.com/ucpp.html</font></u></a></p>
		<p>　　分析任何规模的C或者C++工程，帮助我们更好的理解以及编写文档。</p>
		<p>　　4.2 代码类</p>
		<p>　　(1) CC-Rider</p>
		<p>　　参考站点：<a href="http://www.cc-rider.com/"><u><font color="#0000ff">http://www.cc-rider.com</font></u></a></p>
		<p>　　CC-Rider是用于C/C++程序强大的代码可视化工具，通过交互式浏览、编辑及自<br />动文件来促进程序的维持和发展。</p>
		<p>　　(2) CodeInspect</p>
		<p>　　参考站点：<a href="http://www.yokasoft.com/"><u><font color="#0000ff">http://www.yokasoft.com/</font></u></a></p>
		<p>　　一种新的C/C++代码分析工具。它检查我们的源代码找出非标准的，可能的，以<br />及普通的错误代码。</p>
		<p>　　(3) CodeWizard</p>
		<p>　　参考站点：<a href="http://www.parasoft.com/"><u><font color="#0000ff">http://www.parasoft.com</font></u></a></p>
		<p>　　先进的C/C++源代码分析工具，使用超过500个编码规范自动化地标明危险的，<br />但是编译器不能检查到的代码结构。</p>
		<p>　　(4) C++ Validation Test Suites</p>
		<p>　　参考站点：<a href="http://www.plumhall.com/suites.html"><u><font color="#0000ff">http://www.plumhall.com/suites.html</font></u></a></p>
		<p>　　一组用于测试编译器和库对于标准吻合程度的代码库。</p>
		<p>　　(5) CppRefactory</p>
		<p>　　参考站点：<a href="http://cpptool.sourceforge.net/"><u><font color="#0000ff">http://cpptool.sourceforge.net/</font></u></a></p>
		<p>　　CPPRefactory是一个使得开发者能够重构他们的C++代码的程序。目的是使得C<br />++代码的重构能够尽可能的有效率和简单。</p>
		<p>　　(6) Lzz</p>
		<p>　　参考站点：<a href="http://www.lazycplusplus.com/"><u><font color="#0000ff">http://www.lazycplusplus.com/</font></u></a></p>
		<p>　　Lzz是一个自动化许多C++编程中的体力活的工具。它能够节省我们许多事件并<br />且使得编码更加有乐趣。给出一系列的声明，Lzz会给我们创建头文件和源文件。</p>
		<p>　　(7) QA C++ Generation 2000</p>
		<p>　　参考站点：<a href="http://www.programmingresearch.com/solutions/qacpp.htm"><u><font color="#0000ff">http://www.programmingresearch.com/solutions/qacpp.htm</font></u></a></p>
		<p>　　它关注面向对象的C++源代码，对有关于设计，效率，可靠性，可维护性的部分<br />提出警告信息。</p>
		<p>　　(8) s-mail project - Java to C++DOL</p>
		<p>　　参考站点：<a href="http://sadlocha.strefa.pl/s-mail/ja2dol.html"><u><font color="#0000ff">http://sadlocha.strefa.pl/s-mail/ja2dol.html</font></u></a></p>
		<p>　　把Java源代码翻译为相应的C++源代码的命令行工具。</p>
		<p>　　(9) SNIP from Cleanscape Software International</p>
		<p>　　参考站点：<a href="http://www.cleanscape.net/stdprod/snip/index.html"><u><font color="#0000ff">http://www.cleanscape.net/stdprod/snip/index.html</font></u></a></p>
		<p>　　一个填平编码和设计之间沟壑的易于使用的C++开发工具，节省大量编辑和调试<br />的事件，它还使得开发者能够指定设计模式作为对象模型，自动从对象模型中产生<br />C++的类。</p>
		<p>　　(10) SourceStyler C++</p>
		<p>　　参考站点：<a href="http://www.ochresoftware.com/"><u><font color="#0000ff">http://www.ochresoftware.com/</font></u></a></p>
		<p>　　对C/C++源代码提供完整的格式化和排版控制的工具。提供多于75个的格式化选<br />项以及完全支持ANSI C++。</p>
		<p>　　4.3 编译类</p>
		<p>　　(1) Compilercache</p>
		<p>　　参考站点：<a href="http://www.erikyyy.de/compilercache/"><u><font color="#0000ff">http://www.erikyyy.de/compilercache/</font></u></a></p>
		<p>　　Compilercache是一个对你的C和C++编译器的封装脚本。每次我们进行编译，封<br />装脚本，把编译的结果放入缓存，一旦编译相同的东西，结果将从缓存中取出而不<br />是再次编译。</p>
		<p>　　(2) Ccache</p>
		<p>　　参考站点：<a href="http://ccache.samba.org/"><u><font color="#0000ff">http://ccache.samba.org/</font></u></a></p>
		<p>　　Ccache是一个编译器缓存。它使用起来就像C/C++编译器的缓存预处理器，编译<br />速度通常能提高普通编译过程的5~10倍。</p>
		<p>　　(3) Cmm (C++ with MultiMethods)</p>
		<p>　　参考站点：<a href="http://www.op59.net/cmm/cmm-0.28/users.html"><u><font color="#0000ff">http://www.op59.net/cmm/cmm-0.28/users.html</font></u></a></p>
		<p>　　这是一种C++语言的扩展。读入Cmm源代码输出C++的源代码，功能是对C++语言<br />添加了对multimethod的支持。</p>
		<p>　　(4) The Frost Project</p>
		<p>　　参考站点：<a href="http://frost.flewid.de/"><u><font color="#0000ff">http://frost.flewid.de/</font></u></a></p>
		<p>　　Forst使得你能够在C++程序中像原生的C++特性一样使用multimethod以及虚函<br />数参数。它是一个编译器的外壳。</p>
		<p>　　4.4 测试和调试类</p>
		<p>　　(1) CPPUnit</p>
		<p>　　CppUnit 是个基于 LGPL 的开源项目，最初版本移植自 JUnit，是一个非常优<br />秀的开源测试框架。CppUnit 和 JUnit 一样主要思想来源于极限编程。主要功能就<br />是对单元测试进行管理，并可进行自动化测试。</p>
		<p>　　(2) C++Test</p>
		<p>　　参考站点：<a href="http://www.parasoft.com/"><u><font color="#0000ff">http://www.parasoft.com/</font></u></a></p>
		<p>　　C++ Test是一个单元测试工具，它自动化了C和C++类，函数或者组件的测试。</p>
		<p>
				<br />　　(3) Cantata++</p>
		<p>　　参考站点：<a href="http://www.iplbath.com/products/tools/pt400.shtml"><u><font color="#0000ff">http://www.iplbath.com/products/tools/pt400.shtml</font></u></a></p>
		<p>　　设计的目的是为了满足在合理的经济开销下使用这个工具可以让开发工程师开<br />展单元测试和集成测试的需求.</p>
		<p>　　(4) Purify</p>
		<p>　　参考站点：<a href="http://www-900.ibm.com/cn/software/rational/products/purif"><u><font color="#0000ff">http://www-900.ibm.com/cn/software/rational/products/purif</font></u></a><br />yplus/index.shtml</p>
		<p>　　IBM Rational PurifyPlus是一套完整的运行时分析工具，旨在提高应用程序的<br />可靠性和性能。PurifyPlus将内存错误和泄漏检测、应用程序性能描述、代码覆盖<br />分析等功能组合在一个单一、完整的工具包中。</p>
		<p>　　(5) BoundsChecker</p>
		<p>　　BoundsChecker是一个C++运行时错误检测和调试工具。它通过在Visual Studi<br />o内自动化调试过程加速开发并且缩短上市的周期。BoundsChecker提供清楚，详细<br />的程序错误分析，许多是对C++独有的并且在static，stack和heap内存中检测和诊<br />断错误，以及发现内存和资源的泄漏。　　(6) Insure++</p>
		<p>　　参考站点：<a href="http://www.parasoft.com/"><u><font color="#0000ff">http://www.parasoft.com/</font></u></a></p>
		<p>　　一个自动化的运行时程序测试工具，检查难以察觉的错误,如内存覆盖，内存泄<br />漏，内存分配错误，变量初始化错误，变量定义冲突，指针错误，库错误，逻辑错<br />误和算法错误等。</p>
		<p>　　(7) GlowCode</p>
		<p>　　参考站点：<a href="http://www.glowcode.com/"><u><font color="#0000ff">http://www.glowcode.com/</font></u></a></p>
		<p>　　GlowCode包括内存泄漏检查，code profiler，函数调用跟踪等功能。给C++开<br />发者提供完整的错误诊断，和运行时性能分析工具包。</p>
		<p>　　(8) Stack Spy</p>
		<p>　　参考站点：<a href="http://www.imperioustech.com/"><u><font color="#0000ff">http://www.imperioustech.com/</font></u></a></p>
		<p>　　它能捕捉stack corruption, stack over run, stack overflow等有关栈的错<br />误。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　5，库</p>
		<p>　　在C++中，库的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了<br />设计库来扩充功能要好过设计更多的语法的言论。现实中，C++的库门类繁多，解决<br />的问题也是极其广泛，库从轻量级到重量级的都有。不少都是让人眼界大开，亦或<br />是望而生叹的思维杰作。由于库的数量非常庞大，而且限于笔者水平，其中很多并<br />不了解。所以文中所提的一些库都是比较著名的大型库。</p>
		<p>　　5.1 标准库</p>
		<p>　　标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年<br />，直到标准的出台才正式定型，但是在标准库的实现上却很令人欣慰得看到多种实<br />现，并且已被实践证明为有工业级别强度的佳作。</p>
		<p>　　(1) Dinkumware C++ Library</p>
		<p>　　参考站点：<a href="http://www.dinkumware.com/"><u><font color="#0000ff">http://www.dinkumware.com/</font></u></a></p>
		<p>　　P.J. Plauger编写的高品质的标准库。P.J. Plauger博士是Dr. Dobb's程序设<br />计杰出奖的获得者。其编写的库长期被Microsoft采用，并且最近Borland也取得了<br />其OEM的license，在其C/C++的产品中采用Dinkumware的库。</p>
		<p>　　(2) RogueWave Standard C++ Library</p>
		<p>　　参考站点：<a href="http://www.roguewave.com/"><u><font color="#0000ff">http://www.roguewave.com/</font></u></a></p>
		<p>　　这个库在Borland C++ Builder的早期版本中曾经被采用，后来被其他的库给替<br />换了。笔者不推荐使用。</p>
		<p>　　(3) SGI STL</p>
		<p>　　参考站点：<a href="http://www.roguewave.com/"><u><font color="#0000ff">http://www.roguewave.com/</font></u></a></p>
		<p>　　SGI公司的C++标准模版库。</p>
		<p>　　(4) STLport</p>
		<p>　　参考站点：<a href="http://www.stlport.org/"><u><font color="#0000ff">http://www.stlport.org/</font></u></a></p>
		<p>　　SGI STL库的跨平台可移植版本。</p>
		<p>　　5.2 “准”标准库 - Boost</p>
		<p>　　参考站点：<a href="http://www.boost.org/"><u><font color="#0000ff">http://www.boost.org</font></u></a></p>
		<p>　　国内镜像：<a href="http://www.c-view.org/tech/lib/boost/index.htm"><u><font color="#0000ff">http://www.c-view.org/tech/lib/boost/index.htm</font></u></a></p>
		<p>　　Boost库是一个经过千锤百炼、可移植、提供源代码的C++库，作为标准库的后<br />备，是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起<br />，在C++社区中影响甚大，其成员已近2000人。 Boost库为我们带来了最新、最酷、<br />最实用的技术，是不折不扣的“准”标准库。</p>
		<p>　　Boost中比较有名气的有这么几个库：</p>
		<p>　　Regex</p>
		<p>　　正则表达式库</p>
		<p>　　Spirit</p>
		<p>　　LL parser framework，用C++代码直接表达EBNF</p>
		<p>　　Graph</p>
		<p>　　图组件和算法</p>
		<p>　　Lambda</p>
		<p>　　在调用的地方定义短小匿名的函数对象，很实用的functional功能</p>
		<p>　　concept check</p>
		<p>　　检查泛型编程中的concept</p>
		<p> </p>
		<p>　　Mpl</p>
		<p>　　用模板实现的元编程框架</p>
		<p> </p>
		<p>　　Thread</p>
		<p>　　可移植的C++多线程库</p>
		<p> </p>
		<p>　　Python</p>
		<p>　　把C++类和函数映射到Python之中</p>
		<p>　　Pool</p>
		<p>　　内存池管理</p>
		<p> </p>
		<p>　　smart_ptr</p>
		<p>　　5个智能指针，学习智能指针必读，一份不错的参考是来自CUJ的文章：</p>
		<p>　　Smart Pointers in Boost，哦，这篇文章可以查到，CUJ是提供在线浏览的。<br />中文版见笔者在《Dr. Dobb's Journal软件研发杂志》第7辑上的译文。</p>
		<p>　　Boost总体来说是实用价值很高，质量很高的库。并且由于其对跨平台的强调，<br />对标准C++的强调，是编写平台无关，现代C++的开发者必备的工具。但是Boost中也<br />有很多是实验性质的东西，在实际的开发中实用需要谨慎。并且很多Boost中的库功<br />能堪称对语言功能的扩展，其构造用尽精巧的手法，不要贸然的花费时间研读。Bo<br />ost另外一面，比如Graph这样的库则是具有工业强度，结构良好，非常值得研读的<br />精品代码，并且也可以放心的在产品代码中多多利用。</p>
		<p>　　5.3 GUI</p>
		<p>　　在众多C++的库中，GUI部分的库算是比较繁荣，也比较引人注目的。在实际开<br />发中，GUI库的选择也是非常重要的一件事情，下面我们综述一下可选择的GUI库，<br />各自的特点以及相关工具的支持。</p>
		<p>　　(1) MFC</p>
		<p>　　大名鼎鼎的微软基础类库（Microsoft Foundation Class）。大凡学过VC++的<br />人都应该知道这个库。虽然从技术角度讲，MFC是不大漂亮的，但是它构建于Windo<br />ws API 之上，能够使程序员的工作更容易,编程效率高，减少了大量在建立 Windo<br />ws 程序时必须编写的代码，同时它还提供了所有一般 C++ 编程的优点，例如继承<br />和封装。MFC 编写的程序在各个版本的Windows操作系统上是可移植的，例如，在<br />Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。但<br />是在最近发展以及官方支持上日渐势微。</p>
		<p>　　(2) QT</p>
		<p>　　参考网站：<a href="http://www.trolltech.com/"><u><font color="#0000ff">http://www.trolltech.com/</font></u></a></p>
		<p>　　Qt是Trolltech公司的一个多平台的C++图形用户界面应用程序框架。它提供给<br />应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的<br />很容易扩展，并且允许真正地组件编程。自从1996年早些时候，Qt进入商业领域，<br />它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是流行的Linux桌面环<br />境KDE 的基础，同时它还支持Windows、Macintosh、Unix/X11等多种平台。</p>
		<p>　　(3) WxWindows</p>
		<p>　　参考网站：<a href="http://www.wxwindows.org/"><u><font color="#0000ff">http://www.wxwindows.org/</font></u></a></p>
		<p>　　跨平台的GUI库。因为其类层次极像MFC，所以有文章介绍从MFC到WxWindows的<br />代码移植以实现跨平台的功能。通过多年的开发也是一个日趋完善的GUI库，支持同<br />样不弱于前面两个库。并且是完全开放源代码的。新近的C++ Builder X的GUI设计<br />器就是基于这个库的。</p>
		<p>　　(4) Fox</p>
		<p>　　参考网站：<a href="http://www.fox-toolkit.org/"><u><font color="#0000ff">http://www.fox-toolkit.org/</font></u></a></p>
		<p>　　开放源代码的GUI库。作者从自己亲身的开发经验中得出了一个理想的GUI库应<br />该是什么样子的感受出发，从而开始了对这个库的开发。有兴趣的可以尝试一下。</p>
		<p>
				<br />　　(5) WTL</p>
		<p>　　基于ATL的一个库。因为使用了大量ATL的轻量级手法，模板等技术，在代码尺<br />寸，以及速度优化方面做得非常到位。主要面向的使用群体是开发COM轻量级供网络<br />下载的可视化控件的开发者。</p>
		<p>　　(6) GTK</p>
		<p>　　参考网站：<a href="http://gtkmm.sourceforge.net/"><u><font color="#0000ff">http://gtkmm.sourceforge.net/</font></u></a></p>
		<p>　　GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnome这样的杀手应用。<br />而GTK就是这个库的C++封装版本。</p>
		<p>　　5.4 网络通信</p>
		<p>　　(1) ACE</p>
		<p>　　参考网站：<a href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html"><u><font color="#0000ff">http://www.cs.wustl.edu/~schmidt/ACE.html</font></u></a></p>
		<p>　　C++库的代表，超重量级的网络通信开发框架。ACE自适配通信环境（Adaptive<br /> Communication Environment）是可以自由使用、开放源代码的面向对象框架，在<br />其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++包<br />装外观（Wrapper Facade）和框架组件，可跨越多种平台完成通用的通信软件任务<br />，其中包括：事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通<br />信、共享内存管理、消息路由、分布式服务动态（重）配置、并发执行和同步，等<br />等。</p>
		<p>　　(2) StreamModule</p>
		<p>　　参考网站：<a href="http://www.omnifarious.org/StrMod/"><u><font color="#0000ff">http://www.omnifarious.org/StrMod/</font></u></a></p>
		<p>　　设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容<br />易，而不是用同步的外壳包起异步的本质。</p>
		<p>　　(3) SimpleSocket</p>
		<p>　　参考网站：<a href="http://home.hetnet.nl/%7Elcbokkers/simsock.htm"><u><font color="#0000ff">http://home.hetnet.nl/~lcbokkers/simsock.htm</font></u></a></p>
		<p>　　这个类库让编写基于socket的客户/服务器程序更加容易。</p>
		<p>　　(4) A Stream Socket API for C++</p>
		<p>　　参考网站：<a href="http://www.pcs.cnu.edu/%7Edgame/sockets/socketsC++/sockets.h"><u><font color="#0000ff">http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.h</font></u></a><br />tml</p>
		<p>　　又一个对Socket的封装库。</p>
		<p>　　5.5 XML</p>
		<p>　　(1) Xerces</p>
		<p>　　参考网站：<a href="http://xml.apache.org/xerces-c/"><u><font color="#0000ff">http://xml.apache.org/xerces-c/</font></u></a></p>
		<p>　　Xerces-C++ 是一个非常健壮的XML解析器，它提供了验证，以及SAX和DOM API<br />。XML验证在文档类型定义(Document Type Definition，DTD)方面有很好的支持，<br />并且在2001年12月增加了支持W3C XML Schema 的基本完整的开放标准。</p>
		<p>　　(2) XMLBooster</p>
		<p>　　参考网站：<a href="http://www.xmlbooster.com/"><u><font color="#0000ff">http://www.xmlbooster.com/</font></u></a></p>
		<p>　　这个库通过产生特制的parser的办法极大的提高了XML解析的速度，并且能够产<br />生相应的GUI程序来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了<br />另外一个可行的解决方案。</p>
		<p>　　(3) Pull Parser</p>
		<p>　　参考网站：<a href="http://www.extreme.indiana.edu/xgws/xsoap/xpp/"><u><font color="#0000ff">http://www.extreme.indiana.edu/xgws/xsoap/xpp/</font></u></a></p>
		<p>　　这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parse<br />r，这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。</p>
		<p>
				<br />　　(4) Xalan</p>
		<p>　　参考网站：<a href="http://xml.apache.org/xalan-c/"><u><font color="#0000ff">http://xml.apache.org/xalan-c/</font></u></a></p>
		<p>　　Xalan是一个用于把XML文档转换为HTML，纯文本或者其他XML类型文档的XSLT处<br />理器。</p>
		<p>　　(5) CMarkup</p>
		<p>　　参考网站：<a href="http://www.firstobject.com/xml.htm"><u><font color="#0000ff">http://www.firstobject.com/xml.htm</font></u></a></p>
		<p>　　这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在D<br />OM和SAX之外寻求一点灵感。</p>
		<p>　　(6) libxml++</p>
		<p>　　<a href="http://libxmlplusplus.sourceforge.net/"><u><font color="#0000ff">http://libxmlplusplus.sourceforge.net/</font></u></a></p>
		<p>　　libxml++是对著名的libxml XML解析器的C++封装版本</p>
		<p>　　5.6 科学计算</p>
		<p>　　(1) Blitz++</p>
		<p>　　参考网站：<a href="http://www.oonumerics.org/blitz/"><u><font color="#0000ff">http://www.oonumerics.org/blitz/</font></u></a></p>
		<p>　　Blitz++ 是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具<br />像C++ 一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出<br />的数值程序，比 Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利<br />用C++的template技术，程序执行甚至可以比Fortran更快。Blitz++目前仍在发展中<br />，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以<br />很容易地利用Blitz++所提供的函数来构建。</p>
		<p>　　(2) POOMA</p>
		<p>　　参考网站：<a href="http://www.codesourcery.com/pooma/pooma"><u><font color="#0000ff">http://www.codesourcery.com/pooma/pooma</font></u></a></p>
		<p>　　POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对<br />象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在<br />工业和研究环境中使用。</p>
		<p>　　(3) MTL</p>
		<p>　　参考网站：<a href="http://www.osl.iu.edu/research/mtl/"><u><font color="#0000ff">http://www.osl.iu.edu/research/mtl/</font></u></a></p>
		<p>　　Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式<br />矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如In<br />tel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。</p>
		<p>　　(4) CGAL</p>
		<p>　　参考网站：<a href="http://www.cgal.org/"><u><font color="#0000ff">www.cgal.org</font></u></a></p>
		<p>　　Computational Geometry Algorithms Library的目的是把在计算几何方面的大<br />部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。</p>
		<p>　　5.7 游戏开发</p>
		<p>　　(1) Audio/Video 3D C++ Programming Library</p>
		<p>　　参考网站：<a href="http://www.galacticasoftware.com/products/av/"><u><font color="#0000ff">http://www.galacticasoftware.com/products/av/</font></u></a></p>
		<p>　　***3D是一个跨平台，高性能的C++库。主要的特性是提供3D图形，声效支持（S<br />B,以及S3M），控制接口（键盘，鼠标和遥感），XMS。</p>
		<p>　　(2) KlayGE</p>
		<p>　　参考网站：<a href="http://home.g365.net/enginedev/"><u><font color="#0000ff">http://home.g365.net/enginedev/</font></u></a></p>
		<p>　　国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平<br />台的游戏引擎，并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏<br />先生为中国游戏开发事业所做出的贡献。</p>
		<p>　　(3) OGRE</p>
		<p>　　参考网站：<a href="http://www.ogre3d.org/"><u><font color="#0000ff">http://www.ogre3d.org</font></u></a></p>
		<p>　　OGRE（面向对象的图形渲染引擎）是用C++开发的，使用灵活的面向对象3D引擎<br />。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。<br />引擎中的类库对更底层的系统库（如：Direct3D和OpenGL）的全部使用细节进行了<br />抽象，并提供了基于现实世界对象的接口和其它类。</p>
		<p>　　5.8 线程</p>
		<p>　　(1) C++ Threads</p>
		<p>　　参考网站：<a href="http://threads.sourceforge.net/"><u><font color="#0000ff">http://threads.sourceforge.net/</font></u></a></p>
		<p>　　这个库的目标是给程序员提供易于使用的类，这些类被继承以提供在Linux环境<br />中很难看到的大量的线程方面的功能。</p>
		<p>　　(2) ZThreads</p>
		<p>　　参考网站：<a href="http://zthread.sourceforge.net/"><u><font color="#0000ff">http://zthread.sourceforge.net/</font></u></a></p>
		<p>　　一个先进的面向对象，跨平台的C++线程和同步库。</p>
		<p>　　5.9 序列化</p>
		<p>　　(1) s11n</p>
		<p>　　参考网站：<a href="http://s11n.net/"><u><font color="#0000ff">http://s11n.net/</font></u></a></p>
		<p>　　一个基于STL的C++库，用于序列化POD，STL容器以及用户定义的类型。</p>
		<p>　　(2) Simple XML Persistence Library</p>
		<p>　　参考网站：<a href="http://sxp.sourceforge.net/"><u><font color="#0000ff">http://sxp.sourceforge.net/</font></u></a></p>
		<p>　　这是一个把对象序列化为XML的轻量级的C++库。</p>
		<p>　　5.10 字符串</p>
		<p>　　(1) C++ Str Library</p>
		<p>　　参考网站：<a href="http://www.utilitycode.com/str/"><u><font color="#0000ff">http://www.utilitycode.com/str/</font></u></a></p>
		<p>　　操作字符串和字符的库，支持Windows和支持gcc的多种平台。提供高度优化的<br />代码，并且支持多线程环境和Unicode，同时还有正则表达式的支持。</p>
		<p>　　(2) Common Text Transformation Library</p>
		<p>　　参考网站：<a href="http://cttl.sourceforge.net/"><u><font color="#0000ff">http://cttl.sourceforge.net/</font></u></a></p>
		<p>　　这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较，插入，<br />替换以及用EBNF的语法进行解析。</p>
		<p>　　(3) GRETA</p>
		<p>　　参考网站：<a href="http://research.microsoft.com/projects/greta/"><u><font color="#0000ff">http://research.microsoft.com/projects/greta/</font></u></a></p>
		<p>　　这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况<br />下有非常优秀的表现。</p>
		<p>　　5.11 综合</p>
		<p>　　(1) P::Classes</p>
		<p>　　参考网站：<a href="http://pclasses.com/"><u><font color="#0000ff">http://pclasses.com/</font></u></a></p>
		<p>　　一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot<br />机制，i/o系统包括基于插件的网络协议透明的i/o架构，基于插件的应用程序消息<br />日志框架，访问sql数据库的类等等。</p>
		<p>　　(2) ACDK - Artefaktur Component Development Kit</p>
		<p>　　参考网站：<a href="http://acdk.sourceforge.net/"><u><font color="#0000ff">http://acdk.sourceforge.net/</font></u></a></p>
		<p>　　这是一个平台无关的C++组件框架，类似于Java或者.NET中的框架（反射机制，<br />线程，Unicode，废料收集，I/O，网络，实用工具，XML，等等），以及对Java, P<br />erl, Python, TCL, Lisp, COM 和 CORBA的集成。</p>
		<p>　　(3) dlib C++ library</p>
		<p>　　参考网站：<a href="http://www.cis.ohio-state.edu/%7Ekingd/dlib/"><u><font color="#0000ff">http://www.cis.ohio-state.edu/~kingd/dlib/</font></u></a></p>
		<p>　　各种各样的类的一个综合。大整数，Socket，线程，GUI，容器类,以及浏览目<br />录的API等等。</p>
		<p>　　(4) Chilkat C++ Libraries</p>
		<p>　　参考网站：<a href="http://www.chilkatsoft.com/cpp_libraries.asp"><u><font color="#0000ff">http://www.chilkatsoft.com/cpp_libraries.asp</font></u></a></p>
		<p>　　这是提供zip，e-mail，编码，S/MIME，XML等方面的库。</p>
		<p>　　(5) C++ Portable Types Library (PTypes)</p>
		<p>　　参考网站：<a href="http://www.melikyan.com/ptypes/"><u><font color="#0000ff">http://www.melikyan.com/ptypes/</font></u></a></p>
		<p>　　这是STL的比较简单的替代品，以及可移植的多线程和网络库。</p>
		<p>　　(6) LFC</p>
		<p>　　参考网站：<a href="http://lfc.sourceforge.net/"><u><font color="#0000ff">http://lfc.sourceforge.net/</font></u></a></p>
		<p>　　哦，这又是一个尝试提供一切的C++库</p>
		<p>　　5.12 其他库</p>
		<p>　　(1) Loki</p>
		<p>　　参考网站：<a href="http://www.moderncppdesign.com/"><u><font color="#0000ff">http://www.moderncppdesign.com/</font></u></a></p>
		<p>　　哦，你可能抱怨我早该和Boost一起介绍它，一个实验性质的库。作者在loki中<br />把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过<br />库来提供。同时还提供了智能指针这样比较实用的功能。</p>
		<p>　　(2) ATL</p>
		<p>　　ATL(Active Template Library)</p>
		<p>　　是一组小巧、高效、灵活的类，这些类为创建可互操作的COM组件提供了基本的<br />设施。</p>
		<p>　　(3) FC++: The Functional C++ Library</p>
		<p>　　这个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表<br />作。如果想要在OOP之外寻找另一分的乐趣，可以去看看函数式程序设计的世界。大<br />师Peter Norvig在 “Teach Yourself Programming in Ten Years”一文中就将函<br />数式语言列为至少应当学习的6类编程语言之一。</p>
		<p>　　(4) FACT!</p>
		<p>　　参考网站：<a href="http://www.kfa-juelich.de/zam/FACT/start/index.html"><u><font color="#0000ff">http://www.kfa-juelich.de/zam/FACT/start/index.html</font></u></a></p>
		<p>　　另外一个实现函数式语言特性的库</p>
		<p>　　(5) Crypto++</p>
		<p>　　提供处理密码，消息验证，单向hash，公匙加密系统等功能的免费库。</p>
		<p>　　还有很多非常激动人心或者是极其实用的C++库，限于我们的水平以及文章的篇<br />幅不能包括进来。在对于这些已经包含近来的库的介绍中，由于并不是每一个我们<br />都使用过，所以难免有偏颇之处，请读者见谅。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　6，书籍</p>
		<p>　　以前熊节先生曾撰文评论相对于Java程序设计语言，C++的好书多如牛毛。荣耀<br />先生在《程序员》杂志上撰文《C++程序设计之四书五经》也将本领域内几乎所有的<br />经典书籍作了全面的介绍,任何关于书的评论此时看来便是很多余的了。个人浅见，<br />除非你打算以C++作为唯一兴趣或者生存之本，一般读者确实没有足够的时间和必要<br />将20余本书籍全部阅读。更有参考价值的是荣耀先生的另一篇文章：《至少应该阅<br />读的九本C++著作》，可以从下面的地址浏览到此文：</p>
		<p>　　<a href="http://www.royaloo.com/articles/articles_2003/9CppBooks.htm"><u><font color="#0000ff">http://www.royaloo.com/articles/articles_2003/9CppBooks.htm</font></u></a></p>
		<p>　　下面几本书对于走在C++初学之路上的读者是我们最愿意推荐给大家的：</p>
		<p>　　(1) 《C++ Primer》</p>
		<p>　　哦，也许你会抱怨我们为什么不先介绍TCPL,但对于走在学习之路上的入门者，<br />本书内容更为全面，更为详细易懂，我们称它为“C++的超级宝典”并不过分。配有<br />一本不错的习题解答《C++ Primer Answer Book》可以辅助你的学习之路。</p>
		<p>　　(2) 《Essential C++》</p>
		<p>　　如果说《C++ Primer》是C++领域的超级宝典，那么此书作为掌握C++的大局观<br />当之无愧。正如《.NET大局观》一书能够让读者全揽.NET，本书讲述了C++中最核心<br />的全部主题。书虽不厚，内容精炼，不失为《C++ Primer》读者茶余饭后的主题回<br />顾之作。</p>
		<p>　　(3) 《The C++ Programming Language》</p>
		<p>　　Bjarne为你带来的C++教程，真正能够告诉你怎么用才叫真正的C++的唯一一本<br />书。虽然如同“某某程序设计语言”这样的书籍会给大家一个内容全揽，入门到精<br />通的感觉，但本书确实不太适合初学者阅读。如果你自认为是一名很有经验的C++程<br />序员，那至少也要反复咀嚼Bjarne先生所强调的若干内容。</p>
		<p>　　(4) 《Effective C++》，《More Effective C++》</p>
		<p>　　是的，正如一些C++爱好者经常以读过与没有读过上述两本作品来区分你是否是<br />C++高手。我们也极力推崇这两本著作。在各种介绍C++专家经验的书籍里面，这两<br />本是最贴近语言本质，看后最能够有脱胎换骨感觉的书，读此书你需每日三省汝身<br />。</p>
		<p>　　技术书籍仁者见仁，过多的评论反无太多意义，由读者喜好选择最适合自己的<br />书方为上策。</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　7，资源网站</p>
		<p>　　正如我们可以通过计算机历史上的重要人物了解计算机史的发展，C++相关人物<br />的网站也可以使我们得到最有价值的参考与借鉴，下面的人物我们认为没有介绍的<br />必要，只因下面的人物在C++领域的地位众所周知，我们只将相关的资源进行罗列以<br />供读者学习，他们有的工作于贝尔实验室，有的工作于知名编译器厂商，有的在不<br />断推进语言的标准化，有的为读者撰写了多部千古奇作……<br />　　(1) Bjarne Stroustrup<br />　　<a href="http://www.research.att.com/%7Ebs/"><u><font color="#0000ff">http://www.research.att.com/~bs/</font></u></a></p>
		<p>　　(2) Stanley B. Lippman<br />　　<a href="http://blogs.msdn.com/slippman/"><u><font color="#0000ff">http://blogs.msdn.com/slippman/</font></u></a><br />　　中文版 <a href="http://www.zengyihome.net/slippman/index.htm"><u><font color="#0000ff">http://www.zengyihome.net/slippman/index.htm</font></u></a></p>
		<p>　　(3) Scott Meyers<br />　　<a href="http://www.aristeia.com/"><u><font color="#0000ff">http://www.aristeia.com/</font></u></a></p>
		<p>　　(4) David Musser<br />　　<a href="http://www.cs.rpi.edu/%7Emusser/"><u><font color="#0000ff">http://www.cs.rpi.edu/~musser/</font></u></a></p>
		<p>　　(5) Bruce Eckel<br />　　<a href="http://www.bruceeckel.com/"><u><font color="#0000ff">http://www.bruceeckel.com</font></u></a></p>
		<p>　　(6) Nicolai M. Josuttis<br />　　<a href="http://www.josuttis.com/"><u><font color="#0000ff">http://www.josuttis.com/</font></u></a></p>
		<p>　　(7) Herb Sutter<br />　　<a href="http://www.gotw.ca/"><u><font color="#0000ff">http://www.gotw.ca/</font></u></a></p>
		<p>　　(8) Andrei Alexandrescu<br />　　<a href="http://www.coderncppdesign.com/"><u><font color="#0000ff">http://www.coderncppdesign.com/</font></u></a></p>
		<p>　　(9) 侯捷先生<br />　　<a href="http://www.jjhou.com/"><u><font color="#0000ff">http://www.jjhou.com</font></u></a></p>
		<p>　　(10) 孟岩先生<br />　　先生繁忙于工作，痴迷于技术，暂无个人主页，关于先生的作品可以通过CSDN<br />的专栏和侯先生的主页访问到。</p>
		<p>　　(11) 荣耀先生<br />　　<a href="http://www.royaloo.com/"><u><font color="#0000ff">http://www.royaloo.com/</font></u></a></p>
		<p>　　(12) 潘爱民先生<br />　　<a href="http://www.icst.pku.edu.cn/panaimin/pam_homepage.htm"><u><font color="#0000ff">http://www.icst.pku.edu.cn/panaimin/pam_homepage.htm</font></u></a></p>
		<p>　　除了上述大师的主页外，以下的综合类C++学习参考站点是我们非常愿意向大家<br />推荐的：</p>
		<p>　　(1) CodeProject<br />　　<a href="http://www.codeproject.com/"><u><font color="#0000ff">http://www.codeproject.com</font></u></a></p>
		<p>　　(2) CodeGuru<br />　　<a href="http://www.codeguru.com/"><u><font color="#0000ff">http://www.codeguru.com</font></u></a></p>
		<p>　　(3) Dr. Dobb's Journal<br />　　<a href="http://www.ddj.com/"><u><font color="#0000ff">http://www.ddj.com</font></u></a></p>
		<p>　　(4) C/C++ Users Journal<br />　　<a href="http://www.cuj.com/"><u><font color="#0000ff">http://www.cuj.com</font></u></a></p>
		<p>　　(5) C维视点<br />　　<a href="http://www.c-view.org/"><u><font color="#0000ff">http://www.c-view.org</font></u></a></p>
		<p>　　(6) allaboutprogram<br />　　<a href="http://www.allaboutprogram.com/"><u><font color="#0000ff">http://www.allaboutprogram.com</font></u></a><br />　　其他资料</p>
		<p>　　(1) ISO IEC JTC1/SC22/WG21 - C++：标准C++的权威参考<br />　　<a href="http://anubis.dkuug.dk/jtc1/sc22/wg21/"><u><font color="#0000ff">http://anubis.dkuug.dk/jtc1/sc22/wg21/</font></u></a></p>
		<p>　　(2) C++ FAQ LITE — Frequently Asked Questions: 最为全面的C++FAQ<br />　　<a href="http://www.sunistudio.com/cppfaq/index.html"><u><font color="#0000ff">http://www.sunistudio.com/cppfaq/index.html</font></u></a><br />　　C/C++ 新闻组：<br />　　你不妨尝试从这里提问和回答问题，很多不错的Q&amp;A资源......</p>
		<p>　　(1) .alt.comp.lang.learn.c-c++<br />　　这个简单些，如果你和我一样是个菜鸟</p>
		<p>　　(2) .comp.lang.c++.moderated<br />    嗯，这个显然水平高一些</p>
		<p>　　(3) .comp.std.c++<br />　　如果你需要讨论标准C++相关话题的话</p>
		<p>------------------------------------------------------------------------<br />--------</p>
		<p>　　8，不得不写的结束语</p>
		<p>　　结束的时候也是总结现状，展望未来的时候。虽然C++从脱胎于C开始，一路艰<br />难坎坷的走过来，但是无论如何C++已经取得了工业基础的地位。文章列举的大量相关<br />资源就是最好的证明，而业界的大量用C++写成的产品代码以及大量的C++职业工程<br />师则是最直接的证明。同时，我们可以看到各个高校的计算机专业都开设有C++这门<br />课程，网络上对于C++的学习讨论也从来都没有停过。但是，在Java和.NET两大企业<br />开发平台的围攻下，给人的感觉是C++越来越“不行”了。</p>
		<p>　　C++在面向企业的软件开发中，在开发便捷性等方面的确要比Java和C#差很多，<br />其中一个问题是C++语言本身比较复杂，学习曲线比较陡峭，另外一个问题是C++标<br />准化的时间太长，丧失了很多的壮大机会，耗费了很多精力在厂商的之间的斗争上<br />，而C++的标准库离一个完善的程序开发框架还缺少太多太多的内容，各个第三方的<br />类库和框架又在一致性和完整性上没法和随平台提供的框架相提并论。难道C++真的<br />要退出历史舞台了？</p>
		<p>　　从C++目前的活跃程度，以及应用现状来说是完全能够肯定C++仍然是软件工业<br />的基础，也不会退出历史舞台的。另外从Boost，Loki这些库中我们也能够看到C++<br />的发展非常活跃，对于新技术新思维非常激进，C++仍然广泛受到关注。从ACE在高<br />性能通信领域的应用，以及MTL这样的库在数值计算领域的出色表现，我们可以看到<br />C++在高性能应用场合下的不可替代的作用，而嵌入式系统这样的内存受限开发平台<br />，比如Symbian OS上，C++已经发挥着并且将发挥更大的作用。可以预见的是以后的<br />软件无论上层的应用怎么变，它的底层核心都会是由C/C++这样的系统级软件编写的<br />，比如Java虚拟机，.NET Framwork。因为只有这样的系统级软件才能完全彻底的发<br />挥机器的功能。</p>
		<p>　　需要看到的是两个趋势，一个趋势是C++变得更加复杂，更加学院派，通过模板<br />等有潜力的语法因素构造越来越精巧的库成为了现代C++的热点，虽然在利用库实现<br />新的编程范式，乃至设计模式等方面很有开创意义，也确实产生了一些能够便捷开<br />发的工具，但是更多的是把C++变得更加强大，更加复杂，也更加难懂，似乎也更加<br />学院派，不得不说它正在向边缘化道路发展。另一个趋势是C++在主流的企业应用开<br />发中已经逐渐退出了，ERP这样的企业软件开发中基本上不会考虑C++，除非需要考<br />虑性能或者和遗留代码的集成这些因素。C++退守到系统级别语言，成为软件工业的<br />基础是大势所趋。然而反思一下，真的是退守么？自从STL出现，无数的人风起云涌<br />的开始支持C++,他们狂呼“我看到深夜消失了，目标软件工程的出现。我看到了可<br />维护的代码。”是的，STL在可维护性下做得如此出色。但是又怎样呢？STL为C++铺<br />平了现代软件工程的道路，而在上层应用程序软件开发领域这块场地早不单独属于<br />C++,很多程序设计语言都做得很出色，疯狂的支持者会毫不犹豫地说我们应当支持<br />C++,因为它是世界上最棒的语言。而坦率地说，你的腰杆真的那么硬么？也许只是<br />在逃避一些事实。C++是优秀的，这不可否认，STL的出现让C++一度走上了最辉煌的<br />时刻，然而现在看来……我的一位恩师曾言：真正能够将STL应用得淋漓尽致的人很<br />保守地说国内也不超过200人，或许不加入STL能够使C++向着它应当发展的方向发展<br />的更好，而现在看来，C++也应当回首到真正属于他的那一片圣地上……</p>
		<br />
<img src ="http://www.cppblog.com/erran/aggbug/34178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:14 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CHM格式解析</title><link>http://www.cppblog.com/erran/archive/2007/10/14/34174.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:07:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34174.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34174.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34174.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34174.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34174.html</trackback:ping><description><![CDATA[
		<br />CHM格式解析<br /><br /><br />CHM格式有一个初始化头，占38H字节，后面是header section和到正文 段的偏移量。加在一起，这些被称为文件头。<br />header section一共有两个section，一个是文件目录，另一个包含着文件长度和一些未知信息。<br />初始化头：<br />前
四个字节为ITSF,第二个双字为版本信息，第三双字是文件头的总长度，第四双字值为1，第五双字是一个时间记录，(第一个字节是MSB，第二个字节是
fractional seconds(second
byte),第三个字节可并不确定，第四个字节仅能知道其符号位是确定的。)第六双字是windows语言ID标识，后面16个字节是两个连续的组ID，
分别为{7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}<br />和{7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}<br />后面是header section的表，其中有两项，每项占16个字节，记录着从文件头开始的偏移量和section的长度，各占8个字节。<br />后面还有8个字节的信息，这些在版本2里是没有的。<br />header section 0:<br />第一双字：0x01fe<br />第三双字为文件大小<br />共占5个双字，其余双字均为0<br />header section 1(directory header)<br />开始的四个字节为ITSP，<br />后面的双字为版本号，<br />第三双字为本section长度，<br />第四双字信息未知，<br />第五双字值为0x1000，是目录块的大小，<br />第六双字是quickref section的“密度”，一般是2<br />第七双字是索引树的深度，1表示没有索引，2表示有一层的PMGI数据块。<br />第八双字表示根索引的块号，如果没有索引为-1<br />第九双字是第一个PMGL(listing)的块号<br />第十双字是最后一个PMGL的块号<br />第十一双字是-1<br />第十二双字是目录块的块数<br />第十三双字是windows语言ID标识<br />从这里开始有16个字节的GUID{5D02926A-212E-11D0-9DF9-00A0C922E6EC}<br />然后四个双字不知道是什么东西<br />本段共84个字节<br />从这里开始往后都是数据块，分为两种，一种是列表块(listing chunks),一种是索引块(index chunks)其中列表块的格式如下：<br />开始是四个字节PMGL<br />然后的四个字节是目录块尾部的空白区的长度或是quickref区域的长度<br />第三双字恒为0<br />第四双字是前一个列表块的块号，如果这是第一个块，该值为-1<br />第五双字是后一个列表块的块号，如果这是最后一块，该值为-1<br />从这里开始是目录列表项，按文件名排序，并且大小写不分<br />quickref区是从数据块的后面向前写，每隔n个项出现一个quickref，且n的值为1+(1&lt;&lt;“密度”)，其格式从后至前为<br />第一个字：整个数据块中的项数<br />第二个字：从第0项到第n项之间的偏移量<br />第三个字：从第0项到第2n项之间的偏移量<br />以此类推<br />目录列表的每一项的格式如下：<br />encint型名字长度，后面是UTF-8编码的名称，encint型正文段，encint型偏移量，encint型长度，其中偏移量是从解压缩之后的正文段的开始来计算的，同样长度也是表示解压缩之后的长度。<br />在目录中存在两种文件，用户数据文件和格式信息文件，格式信息文件以两个连续的冒号“：：”开头，用户数据文件以“/”开头。<br />索引块：<br />前四个字节为PMGI<br />后面四个字节是块尾部的quickref或是空白区的长度。<br />从这里开始是目录索引项的开始，每一个目录索引项的结构如下：<br />encint型的名称长度，UFT-8编码的名称，以此名称开始的列表块的块号。<br />quickref的格式和排列与列表块中相同<br />当有索引块的层次较多时，将不再存储数据块号而是存储下一层的索引号。<br />解释一下encint型变量的编码规则：<br />一种可变长度的整型变量，第一个字节只使用低7位，最高位为1表示该字节之后的下一字节的低7位要接在这7位的尾部组成一个数，这样通过移位相加的运算，直到遇到最高位为0的字节，可以组和成一个长度可调节的整数。<br />正文：在版本3中，正文一般紧跟着文件头，而且在文件头表之后有一个双字用来指定其位置。在版本2中，正文部分紧跟着文件头，而且所有此文件夹中的正文部分的第0段放在都放在这个益上，其它的正文段都within content section 0<br />名称列表文件：<br />放在content section 0中，文件名为"::DataSpace/NameList"，其中包含着所有正文段的名称，其格式如下：<br />第一个字：以字计数的文件长度<br />第二个字：文件中的entry数<br />对于每一个entry格式为：<br />第一个字：以字计数的名字长度，不包括最后的NULL结尾符<br />以word 0表示所有entry的结束。<br />名称的编码类似于UFT-16。<br />段的名称目前为止只有两种，Uncompressed和MSCompressed,分别表示自解释文件和Microsoft LZX压缩算法压缩的文件。<br />section data:<br />对
于段号不为0的段，还有一个文件为::DataSpace/Storage/&lt;Section
Name&gt;/Content，里面存放着该段的压缩信息，所以，当解析非0段时，需要两步工作，第一步，取得第0段并将其解圧，取得段名，第二步才
能利用段名找到相应的段<br />其余与格式相关的文件：<br />::DataSpace/Storage/&lt;SectionName&gt;/ControlData <br />共0x20个字节，存储关于压缩的信息<br />第一个双字为在“LZXC”串后的双字个数，在版本2中，此值必为6<br />第二个双字为“LZXC”<br />第三个双字为版本信息，必须大于2<br />第四个双字为LZX reset interval<br />第五个双字为窗口大小<br />第六个双字为缓存大小<br />第七个双字为0，未知信息。<br />::DataSpace/Storage/&lt;SectionName&gt;/SpanInfo <br />存放着未解压的段的长度信息。<br />::DataSpace/Storage/&lt;SectionName&gt;/Transform/List <br />存放GUID列表用于解压缩<br />压缩段：<br />这
一段用LZX压缩，要进行解压缩，先要读取::DataSpace/Storage/&lt;SectionName&gt;/Transform/
{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable，其格式如下：<br />第一个双字为2，估计是版本信息<br />第二个双字是reset table中的entry数<br />第三个双字是8，每一个entry的大小<br />第四个双字是表头长度<br />16个字节的压缩前长度<br />16个字节的压缩后长度<br />16个字节的0x8000 block size for locations below<br />16个字节的0<br />16个字节的第一个非压缩数据块的边界在压缩数据块中的位置信息<br />注意:<br />There
is one change from LZX as defined by Microsoft: After each LZX reset
interval (defined in the ControlData file, but in practice equal to the
window size) of compressed data is processed, the LZX state is fully
reset, as if an entirely new file was being encoded. This allows
semi-random access to the compressed data; you can start reading on any
reset interval boundary using the reset interval size and the reset
table.<img src ="http://www.cppblog.com/erran/aggbug/34174.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:07 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34174.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：牛顿插值算法与实现 </title><link>http://www.cppblog.com/erran/archive/2007/10/14/34172.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/14/34172.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34172.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/14/34172.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34172.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34172.html</trackback:ping><description><![CDATA[
		<font face="Arial">原文：http://blog.csdn.net/nhczp/archive/2007/01/31/1498826.aspx<br />作者：<br /><br /></font>
		<p>
				<font face="Arial">牛顿真是牛，拉格朗日插值法只能算是数学意义上的插值，从插值基函数的巧妙选取，已经构造性的证明了插值法的存在性和惟一性，但是从实现的角度看并不很好，而牛顿很好的解决了这个问题。</font>
		</p>
		<p>
				<font face="Arial">牛顿插值是基于下面这些的公式：</font>
		</p>
		<p>
				<font face="Arial">f[x0,x1,...xk]=(f[x1,...xk]-f[x0,...xk-1])/(xk-x0)<br />f[x]=f(x)<br />f(x)=f[x0]+f[x0,x1](x-x0)+f[x0,x1,x2](x-x0)(x-x1)+...f[x0,...xn](x-x0)...(x-xn-1)+Rn(x)</font>
		</p>
		<p>
				<font face="Arial">前两个是均差的递推关系式，而后一个就是牛顿插值公式，其中N(x)=f(x)-Rn(x)，即目标多项式，Rn(x)是n阶插值余项，我们就是用N(x)去近似f(x)。</font>
		</p>
		<p>
				<font face="Arial">可以构造这样一个均方差表：</font>
		</p>
		<p>
				<font face="Arial">xk   f(xk)   一阶均差   二阶均差 ...<br />x0   f(x0)<br />x1   f(x1)     f[x0,x1]<br />x2   f(x2)     f[x1,x2]     f[x0,x1,x2]<br />...</font>
		</p>
		<p>
				<font face="Arial">如
果有n个点插值，表会有(n*n)/2+n个表项，如果直接编程会有O(n*n)的空间复杂度，编程时做个简单的改进，不难发现在这个表中只有部分数据有
用，对角线（斜行）它们是目标值，用来表示多项式的，左边的两纵行（实际上只需要x一行）以及最底下的一行，表示当前插值的状态。经过改进后只需要O
(n)的空间复杂度。</font>
		</p>
		<p>
				<font face="Arial">两个过程：<br />1，新增加一个点时的更新。只须更新最底下一行数据，其递推关系由均差公式给出，最后算出高一队的均差值，需时O(n)<br />2，插入点完成后如何计算多项式在另外给定点的值N(x)。<br />由牛顿插值公式，最终的表达式为：<br />N(x)=f[x0]+f[x0,x1](x-x0)+f[x0,x1,x2](x-x0)(x-x1)+...f[x0,...xn](x-x0)...(x-xn-1)<br />如果直接将它展开，再算实在麻烦，实际上大可不必这样做，还记得多项式求值的秦九韶算法吗？将多项式‘叠’起来，从内层括号往外一层层拨开，n次多项多的计算，只需要做n次乘法，同样的思想，将上式改写成：<br />N(x)=f[x0]+(x-x0){f[x0,x1]+(x-x1){f[x0,x1,x2]+(x-x2){...{f[x0,...xn-1]+(x-xn-1)f[x0,...xn]}...}<br />就可以同样简单的计算了，时间复杂度O(n)</font>
		</p>
		<p>
				<font face="Arial">综合起来的性能：对于n个点的插值，产生多项式的时间复杂度是O(n*n)，最终进行一个点的计算的时间复杂度是O(n)。</font>
		</p>
		<p>
				<font face="Arial">C++代码实现<br />// file: newton.h<br />#ifndef NEWTON_DEF_<br />#define NEWTON_DEF_<br />class CNewton<br />{<br /> double *f[2];<br /> double *x;<br /> int max;<br /> int n;<br />public:<br /> CNewton(int MaxN);//MaxN 为最大插值点数 可任意设定<br /> ~CNewton();<br /> void InsertPoint(double X,double Y);<br /> double GetValue(double X);<br />};<br />#endif</font>
		</p>
		<p>
				<font face="Arial">// file: newton.cpp<br />#include "newton.h"<br />#include "assert.h"<br />#include "math.h"<br />#ifndef NULL<br />#define NULL 0<br />#endif<br />CNewton::CNewton(int MaxN)<br />{<br /> max=MaxN+1;<br /> n=0;<br /> x=new double[max];<br /> f[0]=new double[max];<br /> f[1]=new double[max];<br /> assert(x!=NULL);<br /> assert(f[0]!=NULL);<br /> assert(f[1]!=NULL);<br />}<br />CNewton::~CNewton()<br />{<br /> if(x)<br />  delete[]x;<br /> if(f[0])<br />  delete[]f[0];<br /> if(f[1])<br />  delete[]f[1];<br />}<br />void CNewton::InsertPoint(double X,double Y)<br />{<br /> int i;<br /> double fw;<br /> assert(n&lt;max);<br /> //重复点检查<br /> for(i=0;i&lt;n;++i)<br />  if(fabs(X-x[i])&lt;1e-5)<br />   return;<br /> //如果确保不会有重复点可删去上面语句<br /> x[n]=X;<br /> fw=Y;<br /> for(i=1;i&lt;=n;++i)<br /> {<br />  double tmp=fw;<br />  fw=(fw-f[1][i-1])/(x[n]-x[n-i]);<br />  f[1][i-1]=tmp;<br /> }<br /> f[0][n]=f[1][n]=fw;<br /> n++;<br />}<br />double CNewton::GetValue(double X)<br />{<br /> if(n==0)<br />  return 0.0;<br /> double s=f[0][n-1];<br /> for(int i=n-2;i&gt;=0;--i)<br /> {<br />  s=s*(X-x[i])+f[0][i];<br /> }<br /> return s;<br />}</font>
		</p>
		<p>
				<font face="Arial">// file: test cpp<br />#include "newton.h"<br />#include "iostream.h"<br />int main(void)<br />{<br /> int n;<br /> double x,y;<br /> CNewton nt(20);<br /> cout&lt;&lt;"输入插入点个数(n&lt;=20)\nn=";<br /> cin&gt;&gt;n;<br /> for(int i=1;i&lt;=n;++i)<br /> {<br />  cout&lt;&lt;"输入第"&lt;&lt;i&lt;&lt;"个点\nx=";<br />  cin&gt;&gt;x;<br />  cout&lt;&lt;"y=";<br />  cin&gt;&gt;y;<br />  nt.InsertPoint(x,y);<br /> }<br /> while(1)<br /> {<br />  cout&lt;&lt;"计算N(x)\nx=";<br />  cin&gt;&gt;x;<br />  cout&lt;&lt;"N("&lt;&lt;x&lt;&lt;")=\n"&lt;&lt;nt.GetValue(x)&lt;&lt;endl;<br />  if(x==0.0)<br />   break;<br /> }<br /> return 0;<br />}</font>
		</p>
		<font face="Arial">
				<br />
		</font>
<img src ="http://www.cppblog.com/erran/aggbug/34172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-14 00:05 <a href="http://www.cppblog.com/erran/archive/2007/10/14/34172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：拉格朗日（lagrange）插值计算 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34171.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 15:57:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34171.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34171.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34171.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34171.html</trackback:ping><description><![CDATA[
		<font color="#000000" face="Arial">
				<br />
		</font>
		<font color="#000000" face="Arial">拉格朗日插值公式：<br />                        n         n<br />  Pn(x(i))=      ∑〔   ∏  （x-x(j)）/（x(k)-x(j)） 〕y(k)<br />                      k=0     j=0 <br />                                 j≠k<br /> <br />  属性：插值计算法<br />                                                                                           n<br />  精度(局部截断误差)：| f(x) - Pn(x) | = [f(ε)] / (n+1)!  ∏  ( x - x(k) )   (注：其中[f(ε)]为f(ε)第n+1次求导的表达式)<br />                                                                                         k=0 <br />                                          <br /> 《数值分析简明教程》-2 Editon -高等教育出版社 -page 18 -算法流程图 </font>
		<p>
				<font color="#000000" face="Arial">  代码维护：2005.6.11  DragonLord<br />**/</font>
		</p>
		<p>
				<font color="#000000" face="Arial">#include&lt;iostream.h&gt;<br />int main()<br />{<br /> float x;//插值<br /> float p[10][2];//已知(x0,y0),(x1,y1)...<br /> int n;//输入已知插值组数<br /> float y,t;<br /> int k;<br /> <br /> cout&lt;&lt;"输入插值组数:"&lt;&lt;endl;<br /> cin&gt;&gt;n;<br /> cout&lt;&lt;"输入"&lt;&lt;n&lt;&lt;"组已知插值数（X,Y）"&lt;&lt;endl;<br />    for(int i=0;i&lt;n;i++)<br /> {<br />  cin&gt;&gt;p[i][0]&gt;&gt;p[i][1];<br /> }<br />    cout&lt;&lt;"输入插值:"&lt;&lt;endl;<br /> cin&gt;&gt;x;<br />  <br /> y=0;<br /> k=0;<br /> <br /> for(k=0;k&lt;n;k++)<br /> {<br />  t=1;<br />  for(i=0;i&lt;n;i++)<br />  {<br />   if(i!=k)<br />   {<br />    t=t*(x-p[i][0])/(p[k][0]-p[i][0]);  //key step<br />   }<br />  }<br />  y=y+p[k][1]*t;</font>
		</p>
		<p>
				<font color="#000000" face="Arial"> }<br /> cout&lt;&lt;"插值结果："&lt;&lt;y&lt;&lt;endl;</font>
		</p>
		<p>
				<font color="#000000" face="Arial">return 0;<br />}</font>
		</p>
		<font color="#000000" face="Arial">
				<br />
		</font>
<img src ="http://www.cppblog.com/erran/aggbug/34171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 23:57 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：DSP芯片介绍 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34170.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 15:48:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34170.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34170.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34170.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34170.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34170.html</trackback:ping><description><![CDATA[
		<br />
		<span style="font-size: 13px;">签于最近汉芯造假丑闻非常流行,这里介绍一下dsp芯片<br />借此机会,给大家一个dsp芯片的概念<br /><a href="http://dsp.blueidea.com/column/weekly/001/145.asp" target="_blank"><font color="#000000">http://dsp.blueidea.com/column/weekly/001/145.asp</font></a><br /><br /><br />1 什么是DSP芯片<br /><br /> 
 
DSP芯片，也称数字信号处理器，是一种具有特殊结构的微处理器。DSP芯片的内部采用程序和数据分开的哈佛结构，具有专门的硬件乘法器，广泛采用流水线
操作，提供特殊的DSP 指令，可以用来快速地实现各种数字信号处理算法。根据数字信号处理的要求，DSP芯片一般具有如下的一些主要特点：<br /><br />（1） 在一个指令周期内可完成一次乘法和一次加法。<br /><br />（2） 程序和数据空间分开，可以同时访问指令和数据。<br /><br />（3） 片内具有快速RAM，通常可通过独立的数据总线在两块中同时访问。<br /><br />（4） 具有低开销或无开销循环及跳转的硬件支持。<br /><br />（5） 快速的中断处理和硬件I/O支持。<br /><br />（6） 具有在单周期内操作的多个硬件地址产生器。<br /><br />（7） 可以并行执行多个操作。<br /><br />（8） 支持流水线操作，使取指、译码和执行等操作可以重叠执行。<br /><br />与通用微处理器相比，DSP芯片的其他通用功能相对较弱些。<br /><br />2 DSP芯片的发展<br /><br /> 
 
世界上第一个单片DSP芯片是1978年AMI公司宣布的S2811，1979年美国Iintel公司发布的商用可编程期间2920是DSP芯片的一个主
要里程碑。这两种芯片内部都没有现代DSP芯片所必须的单周期芯片。 1980年。日本NEC公司推出的μPD7720是第一个具有乘法器的商用DSP
芯片。第一个采用CMOS工艺生产浮点DSP芯片的是日本的Hitachi
公司，它于1982年推出了浮点DSP芯片。1983年，日本的Fujitsu公司推出的MB8764，其指令周期为120ns
，且具有双内部总线，从而处理的吞吐量发生了一个大的飞跃。而第一个高性能的浮点DSP芯片应是AT&amp;T公司于1984年推出的DSP32。<br /><br /> 
  在这么多的DSP芯片种类中，最成功的是美国德克萨斯仪器公司（Texas
Instruments，简称TI）的一系列产品。TI公司灾982年成功推出启迪一代DSP芯片TMS32010及其系列产品TMS32011、
TMS32C10/C14/C15/C16/C17等，之后相继推出了第二代DSP芯片TMS32020、TMS320C25/C26/C28，第三代
DSP芯片TMS32C30/C31/C32，第四代DSP芯片TMS32C40/C44，第五代DSP芯片TMS32C50/C51/C52/C53以
及集多个DSP于一体的高性能DSP芯片TMS32C80/C82等。<br /><br />   
自1980年以来，DSP芯片得到了突飞猛进的发展，DSP芯片的应用越来越广泛。从运算速度来看，MAC（一次乘法和一次加法）时间已经从80年代初的
400ns（如TMS32010）降低到40ns（如TMS32C40），处理能力提高了10多倍。DSP芯片内部关键的乘法器部件从1980年的占模区
的40左右下降到5以下，片内RAM增加一个数量级以上。从制造工艺来看，1980年采用4μ的N沟道MOS工艺，而现在则普遍采用亚微米CMOS工艺。
DSP芯片的引脚数量从1980年的最多64个增加到现在的200个以上，引脚数量的增加，意味着结构灵活性的增加。此外，DSP芯片的发展，是DSP系
统的成本、体积、重量和功耗都有很大程度的下降。<br /><br />3 DSP芯片的分类<br /><br />    DSP的芯片可以按照以下的三种方式进行分类。<br /><br />1. 按基础特性分<br /><br />    这是根据DSP芯片的工作时钟和指令类型来分类的。如果DSP芯片在某时钟频率范围内的任何频率上能正常工作，除计算速度有变化外，没有性能的下降，这类DSP芯片一般称之为静态DSP芯片。<br /><br />    如果有两种或两种以上的DSP芯片,它们的指令集和相应的机器代码机管脚结构相互兼容,则这类DSP芯片称之为一致性的DSP芯片。<br /><br />2. 按数据格式分<br /><br /> 
 
这是根据DSP芯片工作的数据格式来分类的。数据以定点格式工作的DSP芯片称之为定点DSP芯片。以浮点格式工作的称为DSP芯片。不同的浮点DSP芯
片所采用的浮点格式不完全一样，有的DSP芯片采用自定义的浮点格式，有的DSP芯片则采用IEEE的标准浮点格式。<br /><br />3. 按用途分<br /><br />    按照DSP芯片的用途来分，可分为通用型DSP芯片和专用型的DSP芯片。通用型DSP芯片适合普通的DSP应用，如TI公司的一系列DSP芯片。专用型DSP芯片市为特定的DSP运算而设计，更适合特殊的运算，如数字滤波，卷积和FFT等。<br /><br />4 DSP芯片的选择<br /><br />    设计DSP应用系统，选择DSP芯片时非常重要的一个环节。只有选定了DSP芯片才能进一步设计外围电路集系统的其它电路。总的来说，DSP芯片的选择应根据实际的应用系统需要而确定。一般来说，选择DSP芯片时考虑如下诸多因素。<br /><br />1． DSP芯片的运算速度。运算速度是DSP芯片的一个最重要的性能指标，也是选择DSP芯片时所需要考虑的一个主要因素。DSP芯片的运算速度可以用以下几种性能指标来衡量：<br /><br />（1） 指令周期。就是执行一条指令所需要的时间，通常以ns为单位。<br /><br />（2） MAC时间。即一次乘法加上一次加法的时间。<br /><br />（3） FFT执行时间。即运行一个N点FFT程序所需的时间。<br /><br />（4） MIPS。即每秒执行百万条指令。<br /><br />（5） MOPS。即每秒执行百万次操作。<br /><br />（6） MFLOPS。即每秒执行百万次浮点操作。<br /><br />（7） BOPS。即每秒执行十亿次操作。<br /><br />2． DSP芯片的价格。根据一个价格实际的应用情况，确定一个价格适中的DSP芯片。<br /><br />3． DSP芯片的硬件资源。<br /><br />4． DSP芯片的运算速度。<br /><br />5． DSP芯片的开发工具。<br /><br />6． DSP 芯片的功耗。<br /><br />7． 其它的因素，如封装的形式、质量标准、生命周期等。<br /><br />    DSP应用系统的运算量是确定选用处理能力多大的DSP芯片的基础。那么如何确定DSP系统的运算量以选择DSP芯片呢？<br /><br />1． 按样点处理<br /><br /> 
 
按样点处理就是DSP算法对每一个输入样点循环一次。例如；一个采用LMS算法的256抽头德的自适应FIR滤波器，假定每个抽头的计算需要3个MAC周
期，则256抽头计算需要256*3=768个MAC周期。如果采样频率为8KHz，即样点之间的间隔为125μs的时间，DSP芯片的MAC周期为
200μs，则768个周期需要153.6μs的时间，显然无法实时处理，需要选用速度更快的芯片。<br /><br />2． 按帧处理<br /><br /> 
 
有些数字信号处理算法不是每个输入样点循环一次，而是每隔一定的时间间隔（通常称为帧）循环一次。所以选择DSP芯片应该比较一帧内DSP芯片的处理能力
和DSP算法的运算量。假设DSP芯片的指令周期为P（ns），一帧的时间为⊿τ（ns），则该DSP芯片在一帧内所提供的最大运算量为⊿τ/ P
条指令。<br /><br />5 DSP芯片的基本结构<br /><br />DSP芯片的基本结构包括：<br /><br />（1）哈佛结构；<br /><br />（2）流水线操作；<br /><br />（3）专用的硬件乘法器；<br /><br />（4）特殊的DSP指令；<br /><br />（5）快速的指令周期。<br /><br />哈佛结构<br /><br /> 
 
哈佛结构的主要特点是将程序和数据存储在不同的存储空间中，即程序存储器和数据存储器是两个相互独立的存储器，每个存储器独立编址，独立访问。与两个存储
器相对应的是系统中设置了程序总线和数据总线，从而使数据的吞吐率提高了一倍。由于程序和存储器在两个分开的空间中，因此取指和执行能完全重叠。<br /><br />    流水线与哈佛结构相关，DSP芯片广泛采用流水线以减少指令执行的时间，从而增强了处理器的处理能力。处理器可以并行处理二到四条指令，每条指令处于流水线的不同阶段。入图示出一个三级流水线操作的例子。<br /><br />CLLOUT1<br /><br />取指 N N-1 N-2<br /><br />译码 N-1 N N-2<br /><br />执行 N-2 N-1 N<br /><br />图4-1 三级流水线操作<br /><br />专用的硬件乘法器<br /><br />乘法速度越快，DSP处理器的性能越高。由于具有专用的应用乘法器，乘法可在一个指令周期内完成。<br /><br />特殊的DSP指令DSP芯片是采用特殊的指令。<br /><br />    快速的指令周期哈佛结构、流水线操作、专用的硬件乘法器、特殊的DSP指令再加上集成电路的优化设计可使DSP芯片的指令周期在200ns以下。<br /><br />6 DSP系统的特点<br /><br />    数字信号处理系统是以数字信号处理为基础，因此具有数字处理的全部特点：<br /><br />（1） 接口方便。DSP系统与其它以现代数字技术为基础的系统或设备都是相互兼容，这样的系统接口以实现某种功能要比模拟系统与这些系统接口要容易的多。<br /><br />（2） 编程方便。DSP系统种的可编程DSP芯片可使设计人员在开发过程中灵活方便地对软件进行修改和升级。<br /><br />（3） 稳定性好。DSP系统以数字处理为基础，受环境温度以及噪声的影响较小，可靠性高。<br /><br />（4） 精度高。16位数字系统可以达到的精度。<br /><br />（5） 可重复性好。模拟系统的性能受元器件参数性能变化比较大，而数字系统基本上不受影响，因此数字系统便于测试，调试和大规模生产。<br /><br />（6） 集成方便。DSP系统中的数字部件有高度的规范性，便于大规模集成。<br /><br />7 DSP芯片的应用<br /><br /> 
 
自从DSP芯片诞生以来，DSP芯片得到了飞速的发展。DSP芯片高速发展，一方面得益于集成电路的发展，另一方面也得益于巨大的市场。在短短的十多年时
间，DSP芯片已经在信号处理、通信、雷达等许多领域得到广泛的应用。目前，DSP芯片的价格也越来越低，性能价格比日益提高，具有巨大的应用潜力。
DSP芯片的应用主要有：<br /><br />（1） 信号处理--如，数字滤波、自适应滤波、快速傅里叶变换、相关运算、频谱分析、卷积等。<br /><br />（2） 通信--如，调制解调器、自适应均衡、数据加密、数据压缩、回坡抵消、多路复用、传真、扩频通信、纠错编码、波形产生等。<br /><br />（3） 语音--如语音编码、语音合成、语音识别、语音增强、说话人辨认、说话人确认、语音邮件、语音储存等。<br /><br />（4） 图像/图形--如二维和三维图形处理、图像压缩与传输、图像增强、动画、机器人视觉等。<br /><br />（5） 军事--如保密通信、雷达处理、声纳处理、导航等。<br /><br />（6） 仪器仪表--如频谱分析、函数发生、锁相环、地震处理等。<br /><br />（7） 自动控制--如引擎控制、深空、自动驾驶、机器人控制、磁盘控制。<br /><br />（8） 医疗--如助听、超声设备、诊断工具、病人监护等。<br /><br />（9） 家用电器--如高保真音响、音乐合成、音调控制、玩具与游戏、数字电话/电视等</span>
		<br />
		<br />
<img src ="http://www.cppblog.com/erran/aggbug/34170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 23:48 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：逐步认识中断请求IRQ</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34169.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 15:46:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34169.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34169.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34169.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34169.html</trackback:ping><description><![CDATA[
		<font face="Arial, Helvetica, sans-serif">
				<span class="nava">2002-01-25· 
              ·朱柏成··天极硬件频道<br /><br /></span>
		</font>
		<b>一、了解IRQ家族<br /><br /></b>　　IRQ全称为Interrupt
Request，即是“中断请求”的意思（以下使用IRQ称呼）。IRQ的作用就是在我们所用的电脑中，执行硬件中断请求的动作，用来停止其相关硬件的工
作状态，比如我们在打印一份图片，在打印结束时就需要由系统对打印机提出相应的中断请求，来以此结束这个打印的操作。在每台电脑的系统中，是由一个中断控
制器8259或是8259A的芯片（现在此芯片大都集成到其它的芯片内）来控制系统中每个硬件的中断控制。目前共有16组IRQ，去掉其中用来作桥接的一
组IRQ，实际上只有15组IRQ可供硬件调用。这16组IRQ的主要用途如下表：<br /><br /><div align="center"><table table="" border="1" cellpadding="0" cellspacing="0"><tbody><tr><td width="104"><p><strong>IRQ</strong><strong>编号</strong></p></td><td width="139"><p><strong>设备名称</strong></p></td><td width="349"><p><strong>用途</strong></p></td></tr><tr><td width="104"><p>IRQ0</p></td><td width="139"><p>Time</p></td><td width="349"><p>电脑系统计时器</p></td></tr><tr><td width="104"><p>IRQ1</p></td><td width="139"><p>KeyBoard</p></td><td width="349"><p>键盘</p></td></tr><tr><td width="104"><p>IRQ2</p></td><td width="139"><p>Redirect IRQ9</p></td><td width="349"><p>与IRQ9相接，MPU-401 MDI使用该IRQ</p></td></tr><tr><td width="104"><p>IRQ3</p></td><td width="139"><p>COM2</p></td><td width="349"><p>串口设备</p></td></tr><tr><td width="104"><p>IRQ4</p></td><td width="139"><p>COM1</p></td><td width="349"><p>串口设备</p></td></tr><tr><td width="104"><p>IRQ5</p></td><td width="139"><p>LPT2</p></td><td width="349"><p>建议声卡使用该IRQ</p></td></tr><tr><td width="104"><p>IRQ6</p></td><td width="139"><p>FDD</p></td><td width="349"><p>软驱传输控制用</p></td></tr><tr><td width="104"><p>IRQ7</p></td><td width="139"><p>LPT1</p></td><td width="349"><p>打印机传输控制用</p></td></tr><tr><td width="104"><p>IRQ8</p></td><td width="139"><p>CMOS Alert</p></td><td width="349"><p>即时时钟</p></td></tr><tr><td width="104"><p>IRQ9</p></td><td width="139"><p>Redirect IRQ2</p></td><td width="349"><p>与IRQ2相接；可设定给其它硬件使用</p></td></tr><tr><td width="104"><p>IRQ10</p></td><td width="139"><p>Reversed</p></td><td width="349"><p>建议保留给网卡使用该IRQ</p></td></tr><tr><td width="104"><p>IRQ11</p></td><td width="139"><p>Reversed</p></td><td width="349"><p>建议保留给AGP显卡使用</p></td></tr><tr><td width="104"><p>IRQ12</p></td><td width="139"><p>PS/2Mouse</p></td><td width="349"><p>接PS/2鼠标，若无也可设定给其他硬件使用</p></td></tr><tr><td width="104"><p>IRQ13</p></td><td width="139"><p>FPU</p></td><td width="349"><p>协处理器用，例如FPU（浮点运算器）</p></td></tr><tr><td width="104"><p>IRQ14</p></td><td width="139"><p>Primary IDE</p></td><td width="349"><p>主硬盘传输控制用</p></td></tr><tr><td width="104"><p>IRQ15</p></td><td width="139"><p>Secondary Ide</p></td><td width="349"><p>从硬盘传输控制用</p></td></tr></tbody></table><br /><div align="left"><span class="txt"><b>二、掌握</b><b>IRQ</b><b>家族的相处之道<br /><br /></b>　　现在的
windows操作系统已经运用PNP技术，这种“即插即用”的功能可以将中断进行自动分配，大大简化了用户的操作。不过这种PNP技术也有它的弱点，那
就是如果不能认出要安装的新设备，那么自动分配中断时就会产生冲突。我们日常所用的，对于IRQ的设置也不尽相同，所以在安装新硬件的时候，系统往往并不
能自动检测正确的IRQ来分配给所用调用的硬件，这就会造成此硬件设备或是原来的旧硬件出现不能正常工作的现象。现在新的硬件产品层出不穷，各种产品又相
互兼容，功能类似，这就导致了操作系统常常不能正确检测出新设备，中断冲突也就不可避免了。其实这是因为系统自动将该硬件的IRQ分配给了其它与此IRQ
相同的硬件上，从而发生冲突使硬件不能正常工作。一般如果遇到这种情况，只要将新旧两个硬件的IRQ配置手动调开就可以解决了。手动配置IRQ时，最好检
查有无保留中断（IRQ），不要让其他设备使用该中断号，以免引起新的中断冲突，造成系统死机。<br /><br />　　以下使用目前比较受欢迎的KT266A主板Epox 8KHA+为例，介绍IRQ家族的和平相处之道。我从一些外国网站的论坛知道有关Epox 8KHA+在Bios 将Set PnP OS选项设定为 NO的时候，IRQ的自动配置情况：<br /><br /><table table="" align="center" border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top" width="135"><p>插槽</p></td><td valign="top" width="89"><p>INT--A</p></td><td valign="top" width="94"><p>INT—B</p></td><td valign="top" width="94"><p>INT—C</p></td><td valign="top" width="94"><p>INT—D</p></td></tr><tr><td valign="top" width="135"><p>PCI插槽1</p></td><td valign="top" width="89"><p>共享</p></td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>PCI插槽2</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>PCI插槽3</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>PCI插槽4</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td></tr><tr><td valign="top" width="135"><p>PCI插槽5</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>PCI插槽6</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td></tr><tr><td valign="top" width="135"><p>AGP插槽</p></td><td valign="top" width="89"><p>共享</p></td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>主板声卡</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td><td valign="top" width="94">  </td></tr><tr><td valign="top" width="135"><p>USB控制器</p></td><td valign="top" width="89">  </td><td valign="top" width="94">  </td><td valign="top" width="94">  </td><td valign="top" width="94"><p>共享</p></td></tr></tbody></table><br /><br />　　从以上默认的IRQ自动配置可以得出以下配件最佳安装方法一览表：<br /><br /><table table="" align="center" border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top" width="112"><p>配件</p></td><td valign="top" width="187"><p>安装位置</p></td><td valign="top" width="245"><p>默认的IRQ自动配置</p></td></tr><tr><td valign="top" width="112"><p>AGP显卡</p></td><td valign="top" width="187"><p>AGP插槽</p></td><td valign="top" width="245"><p>与PCI 插槽 1共享IRQ</p></td></tr><tr><td valign="top" width="112"><p>PCI显卡</p></td><td valign="top" width="187"><p>PCI 插槽1</p></td><td valign="top" width="245"><p>与AGP插槽共享IRQ</p></td></tr><tr><td valign="top" width="112"><p>IDE RAID 卡</p></td><td valign="top" width="187"><p>PCI 插槽2</p></td><td valign="top" width="245"><p>独立使用IRQ（不共享IRQ）</p></td></tr><tr><td valign="top" width="112"><p>声卡</p></td><td valign="top" width="187"><p>PCI 插槽 3或插槽 5</p></td><td valign="top" width="245"><p>与主板上的AC97声卡共享IRQ</p></td></tr><tr><td valign="top" width="112"><p>网卡、内置猫</p></td><td valign="top" width="187"><p>PCI 插槽 4或插槽 6</p></td><td valign="top" width="245"><p>与主板上的USB控制器共享IRQ</p></td></tr></tbody></table><br /><br />　　只要我们把配件安装正确，BIOS按照出厂时的设置，这时系统会自动设置IRQ，使得各个IRQ合理分配，使系统工作正常。<br /><br /></span><b></b></div></div><span class="txt"><b>三、解决</b><b>IRQ</b><b>冲突<br /><br /></b>　　常见的IRQ冲突现象有系统不能正确检测出新设备、有些硬件工作不正常（如声卡不发声），严重的会出现死机。这往往没有正确安装硬件或手动调整IRQ不当引起的。<br /><br />　　要解决中断冲突，首先我们要知道系统中冲突的设备，做法是在控制面板中双击“系统”图标，查看设备管理器中的各设备。一般有“？”和“！”的设备要注意了，有问题的设备就是它们了。解决方法有分两步做：<br /><br /> 　　第一步、先删去有“？”和“！”的设备，然单击刷新，让计算机自己再认一遍这些设备。这样做是因为部分有“？”和“！”的设备可能是驱动程序安装有误，再重装一遍或升级驱动程序可解决问题。<br /><br />
　　第二步、如果上面一步还是不能解决问题，现在多半是中断冲突了，那我们只能手动调整来解决中断冲突。在系统＝＞设备管理器＝＞属性　中我们可以看到系
统资源分配的情况，通过查看此项就可从中了解到哪些系统资源被占用，哪些系统资源还没有用，用户做相应的调整即可（通常换另外一条插槽再手动配置IRQ，
问题就解决了）。<br /><br />　　以下使用Epox 8KHA+ KT266A主板为例，介绍手动配置硬件IRQ时的安装方法和最优的设置方法：<br /><br />1、开机，进入CMOS设置界面，它是AWARD公司的BIOS，进入“PNP/PCI CONFIGURATION” （见图一） 
<p align="center"><img src="http://www.yesky.com/20020125/lzh0125-image001.jpg" /><br />图一</p>2、
将“PNP OS Installed”改为Yes，将“Resources controlled
By”改为Auto，利用方向箭头和+，-符号键来设置INT Pin X（x=1,2,3,4）。在菜单左边的INT Pin
X的新设置值（红色部分），在右边显示设置的设备。例如INT Pin
1设定为11，对应IRQ为11的设备（显卡）在右边帮助栏显示出来（见图二）。完成对INT Pin
X的设置后保存（按F10）后重启动。启动后计算机检测正常，Windows的PNP功能会找到并且安装新硬件。.以下是手动配置硬件IRQ时的安装方法
和最优IRQ值的设置一览表：<br /><br /><table table="" align="center" border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top" width="105"><p>配件</p></td><td valign="top" width="103"><p>安装位置</p></td><td valign="top" width="115"><p>BIOS设置项</p></td><td valign="top" width="97"><p>设置IRQ值</p></td><td valign="top" width="143"><p>备注</p></td></tr><tr><td valign="top" width="105"><p>AGP显卡</p></td><td valign="top" width="103"><p>AGP插槽</p></td><td valign="top" width="115"><p>INT-Pin1</p></td><td valign="top" width="97"><p>11</p></td><td valign="top" width="143">  </td></tr><tr><td valign="top" width="105"><p>PCI显卡</p></td><td valign="top" width="103"><p>PCI 插槽1</p></td><td valign="top" width="115"><p>INT-Pin1</p></td><td valign="top" width="97"><p>11</p></td><td valign="top" width="143"><p>不能与AGP显卡共同使用</p></td></tr><tr><td valign="top" width="105"><p>声卡</p></td><td valign="top" width="103"><p>PCI 插槽 3或插槽 5</p></td><td valign="top" width="115"><p>INT-Pin2</p></td><td valign="top" width="97"><p>5</p></td><td valign="top" width="143"><p>不要忘记把在bios菜单中屏蔽主板自带的声卡</p></td></tr><tr><td valign="top" width="105"><p>USB</p></td><td valign="top" width="103">  </td><td valign="top" width="115"><p>INT-Pin3</p></td><td valign="top" width="97"><p>9</p></td><td valign="top" width="143">  </td></tr><tr><td valign="top" width="105"><p>网卡、内置modem</p></td><td valign="top" width="103"><p>PCI 插槽 4或插槽 6</p></td><td valign="top" width="115"><p>INT-Pin4</p></td><td valign="top" width="97"><p>10或9</p></td><td valign="top" width="143"><p>采用IRQ10比采用IRQ9快</p></td></tr></tbody></table><p align="center"><img src="http://www.yesky.com/20020125/lzh0125-image003.jpg" /><br />图二</p></span><div align="left"><span class="txt"><p align="center"><br /></p></span><span class="txt"><b>四、设置</b><b>IRQ</b><b>时注意的问题<br /><br /></b>　　笔者的电脑在bios的设定如下：<br /><br />PnP OS -&gt; NO <br />Modem use IRQ -&gt; N/A <br />Unika GeForce Mx200-&gt; IRQ 11 <br />SB live! Value -&gt; IRQ 5 <br />Star Internal Modem -&gt;IRQ 10 <br />onboard sound  -&gt;DISABLED<br /><br />game  port -&gt; DISABLED<br /><br />midi   port -&gt; DISABLED<br /><br /> 　　但事实上在windows的系统信息中显示以下配置：<br /><br />Unika GeForce Mx200 -&gt; 11 <br />SB Live! Value -&gt; IRQ 10 <br />Star Internal Modem -&gt; IRQ 3 <br />USB controller -&gt; IRQ 3 <br />ACPI -&gt; IRQ 9<br /><br />　
　为什么会出现这种情况呢？原来如果手动配置INT Pin
4（控制PCI插槽4和6，并且控制主板上的USB）分配中断点9，那么当你安装支持ACPI的Windows操作系统时，
PCI插槽4和6和主板上的USB控制器的实际中断点会被分配其他空闲的中断资源。因为安装时Windows默认打开ACPI功能，并且会占用IRQ
9或7 或11其中一个IRQ，通常Windows操作系统的ACPI中断点默认是9。如果关闭ACPI，你的系统会减少一点发热并可以提高3
D的性能。但如果在打开ACPI功能时一切运作正常，我建议不要改动这项设置。因为如果关闭ACPI，就不能使用即插即用功能，这时会出现Windows
不能探测任何新安装的硬件，也可能会出现多个设备一起使用同一个IRQ（例如声卡，内置modem，显卡都使用IRQ 11）。<br /><br />　　一些
VIA KT133A 芯片主板在安装支持ACPI 的Windows 2000 或Win
XP时，会使主板自带的modem（或内置modem）的IRQ自动设为
9，和ACPI功能共享中断。如果你不使用主板自带的modem或内置modem， 那么要将Modem Use IRQ" 设为 N/A
(默认中断请求是3 )。你将"Integrated Peripheral \ Super IO Device\Onboard Serial
Port 2"设为 DISABLED 并且在Power Management Setup\Modem Use
IRQ设为DISABLED来屏蔽com1通信口 （com1的默认中断请求是3）， 这样Epox 8KHA+主板（其他VIA
KT266A芯片主板也一样）会根据bios里的设置而自动合理分配各个中断。这时PCI插槽4和6和主板上的USB控制器的实际中断点自动分配为3 。<br /><br />　
　另外创新的一些声卡如SBLive是需要2个IRQ，其中一个对当前的声卡的支持(IRQ 10)，而另一个IRQ (IRQ
5)用于对那些仍然需要声霸卡（Sound
Blaster）兼容模式的老游戏的支持。用户可以在设备管理器中，展开声音视频游戏控制器中看见Legacy Audio
Drivers，双击进入看它是否占用任何IRQ，如果用户不玩老游戏（如比较旧的DOS游戏）你可以在Legacy Audio
Drivers的属性框中选择禁用该设备。<br /><br /><b>五、其他技巧<br /><br /></b>1.删除设备的驱动程序，关机后将外设拔出，置重新安装，让系统重新检测。<br /><br />2.如果你使用内置调制解调器，可以在bois菜单中关闭com2,这可以节省出IRQ3,供内置调制解调器使用。<br /><br />3.屏蔽那些暂时不需要使用的硬件，例如USB控制器，节省出IRQ以供其他急需使用的重要设备。<br /><br /><br /></span><span class="txt"></span></div><div align="left"><div align="left"><span class="txt"></span><br /><span class="txt"></span></div><br /><span class="txt"></span></div><img src ="http://www.cppblog.com/erran/aggbug/34169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 23:46 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：DSP的特点</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34167.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 15:23:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34167.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34167.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34167.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34167.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34167.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Arial">原文：http://www.mcublog.com/blog/user1/5157/archives/2006/16413.html<br /></font>
		</p>
		<p>
				<font face="Arial">DSP的特点</font>
		</p>
		<p>
				<font face="Arial">对于没有使用过DSP的初学者来说，第一个困惑就是DSP其他的嵌入式处理器究竟有什么不同，它和单片机，ARM有什么区别。事实上，DSP也是一种嵌入式处理器，它完全可以完成单片机的功能。<br />唯
一的重要的区别在于DSP支持单时钟周期的"乘-加"运算。这几乎是所有厂家的DSP芯片的一个共有特征。几乎所有的DSP处理器的指令集中都会有一条
MAC指令，这条指令可以把两个操作数从RAM中取出相乘，然后加到一个累加器中，所有这些操作都在一个时钟周期内完成。拥有这样一条指令的处理器就具备
了<br />DSP功能。<br />具有这条指令就称之为数字信号处理器的原因在于，所有的数字信号处理算法中最为常见的算术操作就是"乘-加"。这是因为数
字信号处理中大量使用了内积，或称"点积"的运算。无论是FIR滤波，FFT，信号相关，数字混频，下变频。所有这些数字信号处理的运算经常是将输入信号
与一个系数表或者与一个本地参考信号相乘然后积分（累加），这就表现为将两个向量（或称序列）进行点积，在编程上就变成将输入的采样放在一个循环
buffer里，本地的系数表或参考信号也放在一个buffer里，然后使用两个指针指向这两个buffer。这样就可以在一个loop里面使用一个
MAC指令将二者进行点积运算。这样的点积运算对与处理器来说是最快的，因为仅需一个始终周期就可以完成一次乘加。<br />了解DSP的这一特点后，当我们设计一个嵌入式系统时，首先要考虑处理器所实现的算法中是否有点积运算<br />，即是否要经常进行两个数组的乘加，（记住数字滤波，相关等都表现为两个数组的点积）如果有的话，每秒要做多少次，这样就能够决定是否采用DSP，采用多高性能的DSP了。</font>
		</p>
		<p>
				<font face="Arial">浮点与定点</font>
		</p>
		<p>
				<font face="Arial">浮点与定点也是经常是初学者困惑的问题，在选择DSP器件的时候，是采用浮点还是采用定点，如果用定点是16位还是32位？其实这个问题和你的算法所要求的信号的动态范围有关。<br />定
点的计算不过是把一个数据当作整数来处理，通常AD采样来的都是整数，这个数相对于真实的模拟信号有一个刻度因子，大家都知道用一个16位的AD去采样一
个0到5V的信号，那么AD输出的整数除以2^16再乘以5V就是对应的电压。在定点DSP中是直接对这个16位的采样进行处理，并不将它转换成以小数表
示的电压，因为定点DSP无法以足够的精度表示一个小数，它只能对整数进行计算。<br />而浮点DSP的优势在于它可以把这个采样得到的整数转换成小数表示的电压，并不损失精度（这个小数用科学记数法来表示），原因在于科学记数法可以表示很大的动态范围的一个信号，以IEEE754浮点数为例，<br />单精度浮点格式： [31] 1位符号 [30-23]8位指数 [22-00]23位小数 <br />这
样的能表示的最小的数是+-2^-149,最大的数是+-（2-2^23)*2^127.动态范围为20*log(最大的数/最小的数）=
1667.6dB
这样大的动态范围使得我们在编程的时候几乎不必考虑乘法和累加的溢出，而如果使用定点处理器编程，对计算结果进行舍入和移位则是家常便饭，这在一定程度上
会损失是精度。原因在于定点处理处理的信号的动态范围有限，比如16位定点DSP，可以表示整数范围为1-65536，其动态范围为20*log
(65536/1)=96dB.对于32定点DSP，动态范围为20*log(2^32/1)=192dB,远小于32位ieee浮点数的
1667.6dB,但是，实际上192dB对绝大多数应用所处理的信号已经足够了。<br />由于AD转换器的位数限制，一般输入信号的动态范围都比较小，
但在DSP的信号处理中，由于点积运算会使中间节点信号的动态范围增加，所以主要考虑信号处理流程中中间结果的动态范围，以及算法对中间结果的精度要求，
来选择相应的DSP。另外就是浮点的DSP更易于编程，定点DSP编程中程序员要不断调整中间结果的P，Q值，实际就是不断对中间结果进行移位调整和舍
入。</font>
		</p>
		<p>
				<font face="Arial">DSP与RTOS</font>
		</p>
		<p>
				<font face="Arial">TI的CCS提供BIOS，ADI的VDSP提供VDK，都是基于各自DSP的嵌入式多任务内核。DSP编程可以用单用C，也可以用汇编，或者二者
结合，一般软件编译工具都提供了很好的支持。我不想在这里多说BIOS，VDK怎么用这在相应的文档里说的很详细。我想给初学者说说DSP的RTOS原
理。用短短几段话说这个复杂的东西也是挑战！^_^</font>
		</p>
		<p>
				<font face="Arial">其实DSP的RTOS和基于其他处理器的通用RTOS没什么大的区别，现在几乎人人皆知的uCOSii也很容易移植到DSP上来，只要把寄存器保存与恢复部分和堆栈部分改改就可以。一般在用BIOS和VDK之前，先看看操作系统原理的书比较好。uCOS那本书也不错。<br />BIOS
和VDK其实是一个RTOS内核函数集，DSP的应用程序会和这些函数连接成一个可执行文件。其实实现一个简单的多任务内核并不复杂，首先定义好内核的各
种数据结构，然后写一个scheduler函数，功能是从所有就绪任务中（通过查找就绪任务队列或就绪任务表）找出优先级最高的任务，并恢复其执行。然后
在此基础上写几个用于任务间通信的函数就可以了，比如event,message box,等等。<br />RTOS一般采用抢先式的任务调度方式，举例说
当任务A等待的资源available的时候,DSP会执行一个任务调度函数scheduler,这个函数会检查当前任务是否比任务A优先级低，如果是的
话，就会把它当前挂起，然后把任务A保存在堆栈里寄存器值全部pop到DSP处理器中(这就是所谓的任务现场恢复）。接着scheduler还会把从堆栈
中取出任务A挂起时的程序执行的地址，pop到PC，使任务A继续执行。这样当前任务就被任务A抢先了。<br />使用RTOS之后，每个任务都会有一个主
函数，这个函数的起始地址就是该任务的入口。一般每个任务的主函数里有一个死循环，这个循环使该任务周期地执行，完成一部分算法模块的功能，其实这个函数
跟普通函数没任何区别，类似于C语言中的main函数。一个任务创建的时候，RTOS会把这个函数入口地址压入任务的堆栈中，好象这个函数（任务）刚发生
过一次中断一样。一旦这个新创建任务的优先级在就绪队列中是最高的，RTOS就会从其堆栈中弹出其入口地址开始执行。<br />有一个疑问是，不使用
RTOS，而是简单使用一个主循环在程序中调用各个函数模块，一样可以实现软件的调度执行。那么，这种常用的方法与使用RTOS相比有什么区别呢？其实，
使用主循环的方法不过是一种没有优先级的顺序执行的调度策略而已。这种方法的缺点在于，主循环中调用的各个函数是顺序执行的，那么，即使是一个无关紧要的
函数（比如闪烁一个LED），只要他不主动返回，也会一直执行直到结束，这时，如果发生一个重要的事件（比如DMA buffer full
中断)，就会得不到及时的响应和处理，只能等到那个闪烁LED的函数执行完毕。这样就使整个DSP处理的优先次序十分不合理。而在使用了RTOS之后，当
一个重要的事件发生时，中断处理会进入RTOS，并调用scheduler,这时scheduler
会让处理这一事件的任务抢占DSP处理器（因为它的优先级高）。而哪个闪烁LED任务即使晚执行几毫秒都没任何影响。这样整个DSP的调度策略就十分合
理。<br />RTOS要说的内容太多，我只能讲一下自己的一点体会吧</font>
		</p>
		<p>
				<font face="Arial">DSP与正（余）弦波</font>
		</p>
		<p>
				<font face="Arial">在DSP的应用中，我们经常要用到三角函数，或者合成一个正（余）弦波。这是因为我们喜欢把信号通过傅立叶变换映射到三角函数空间来理解信号的频率
特性。信号处理的一些计算技巧都需要在DSP软件中进行三角函数计算。然而三角函数计算是非线性的计算，DSP并没有专门的指令来求一个数的正弦或余弦。
于是我们需要用线性方法来近似求解。<br />一个直接的想法是用多项式拟合，这也正是大多数DSP
C编译器提供正余弦库函数所采用的方法。其原理是把三角函数向函数空间{1，x,x^2,x^3....}上投影，从而获得一系列的系数，用这些系数就可
以拟合出三角函数。比如，我们在[0，pi/2]区间上拟合sin,只需在matlab中输入以下命令：<br />x=0:0.05:pi/2;<br />p=polyfit(x,sin(x),5)<br />就得到5阶的多项式系数：<br />p =<br />0.00581052047605 0.00580963216172 -0.17193865685360<br />0.00209002716293 0.99969270087312 0.00000809543448<br />于是在[0，pi/2]区间上：<br />sin(x)= 0.00000809543448+0.99969270087312*x+ 0.00209002716293*x^2-0.17193865685360*x^3+<br />0.00580963216172*x^4+0.00581052047605*x^5<br />于是在DSP程序中，我们可以通过用乘加（MAC）指令计算这个多项式来近似求得sin(x)<br />当然如果用定点DSP还要把P这个多项式系数表用一定的Q值来改写成定点数。</font>
		</p>
		<p>
				<font face="Arial">这样的三角函数计算一般都需要几十个cycle 的开销。这对于某些场合是不能容忍的</font>
		</p>
		<p>
				<font face="Arial">另一种更快的方法是借助于查表，比如，我们将[0，pi/2]分成32个区间，每个区间长度就为pi/64,在每个区间上我们使用直线段拟合sin曲线，每个区间线段起点的正弦值和线段斜率事先算好，存在RAM里，这样就需要在在RAM里存储64个<br />常数：<br />32个起点的精确的正弦值（事先算好）： s[32]={0,sin(pi/64),sin(pi/32),sin(pi/16)....}<br />32个线段的斜率： f[32]={0.049,.....}<br />对于输入的每一个x,先根据其大小找到所在区间i，通常x用定点表示，一般取其高几位就是系数i了，然 后通过下式即可求出sin(x)：<br />sin(x)= s[i]*f[i]<br />这样一般只需几个CYCLE就可以算出正弦值，如果需要更高的精度，可以将区间分得更细，当然，也就需 要更多的RAM去存储常数表。<br />事实上，不仅三角函数，其他的各种非线性函数都是这样近似计算的。 </font>
		</p>
<img src ="http://www.cppblog.com/erran/aggbug/34167.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 23:23 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34167.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：做DSP最应该懂得157个问题（回答）</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34166.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 15:04:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34166.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34166.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34166.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34166.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34166.html</trackback:ping><description><![CDATA[
		<font face="Arial">
				<span class="javascript" id="text352539">
						<br />做DSP最应该懂得157个问题（回答）<br /><br /><br />四.5V/3.3V如何混接？<br />TI
DSP的发展同集成电路的发展一样，新的DSP都是3.3V的，但目前还有许多外围电路是5V的，因此在DSP系统中，经常有5V和3.3V的DSP混接
问题。在这些系统中，应注意： 1)DSP输出给5V的电路（如D/A），无需加任何缓冲电路，可以直接连接。
2)DSP输入5V的信号（如A/D），由于输入信号的电压&gt;4V，超过了DSP的电源电压，DSP的外部信号没有保护电路，需要加缓冲，如
74LVC245等，将5V信号变换成3.3V的信号。 3)仿真器的JTAG口的信号也必须为3.3V，否则有可能损坏DSP。 <br /><br />五.为什么要片内RAM大的DSP效率高？<br />目
前DSP发展的片内存储器RAM越来越大，要设计高效的DSP系统，就应该选择片内RAM较大的DSP。片内RAM同片外存储器相比，有以下优点：
1)片内RAM的速度较快，可以保证DSP无等待运行。
2)对于C2000/C3x/C5000系列，部分片内存储器可以在一个指令周期内访问两次，使得指令可以更加高效。
3)片内RAM运行稳定，不受外部的干扰影响，也不会干扰外部。 4)DSP片内多总线，在访问片内RAM时，不会影响其它总线的访问，效率较高。<br /><br />六.为什么DSP从5V发展成3.3V？<br />超
大规模集成电路的发展从1um，发展到目前的0.1um，芯片的电源电压也随之降低，功耗也随之降低。DSP也同样从5V发展到目前的3.3V，核心电压
发展到1V。目前主流的DSP的外围均已发展为3.3V，5V的DSP的价格和功耗都价格，以逐渐被3.3V的DSP取代。 <br /><br />七如何选择DSP的电源芯片？<br />TMS320LF24xx：TPS7333QD，5V变3.3V，最大500mA。 <br />TMS320VC33： TPS73HD318PWP，5V变3.3V和1.8V，最大750mA。 <br />TMS320VC54xx：TPS73HD318PWP，5V变3.3V和1.8V，最大750mA； TPS73HD301PWP，5V变3.3V和可调，最大750mA。 <br />TMS320VC55xx：TPS73HD301PWP，5V变3.3V和可调，最大750mA。 <br />TMS320C6000： PT6931，TPS56000，最大3A。 <br /><br />八.软件等待的如何使用？<br />DSP的指令周期较快，访问慢速存储器或外设时需加入等待。等待分硬件等待和软件等待，每一个系列的等待不完全相同。 <br />1)对于C2000系列： 硬件等待信号为READY，高电平时不等待。 软件等待由WSGR寄存器决定，可以加入最多7个等待。其中程序存储器和数据存储器及I/O可以分别设置。 <br />2)对于C3x系列： 硬件等待信号为/RDY，低电平是不等待。 软件等待由总线控制寄存器中的SWW和WTCNY决定，可以加入最多7个等待，但等待是不分段的，除了片内之外全空间有效。 <br />3)对于C5000系列： 硬件等待信号为READY，高电平时不等待。 软件等待由SWWCR和SWWSR寄存器决定，可以加入最多14个等待。其中程序存储器、控制程序存储器和数据存储器及I/O可以分别设置。 <br />4)对于C6000系列（只限于非同步存储器或外设）： 硬件等待信号为ARDY，高电平时不等待。 软件等待由外部存储器接口控制寄存器决定，总线访问外部存储器或设备的时序可以设置，可以方便的同异步的存储器或外设接口。 <br /><br />九.中断向量为什么要重定位？<br />为了方便DSP存储器的配置，一般DSP的中断向量可以重新定位，即可以通过设置寄存器放在存储器空间的任何地方。 注意：C2000的中断向量不能重定位。 <br /><br />十.DSP的最高主频能从芯片型号中获得吗？<br />TI的DSP最高主频可以从芯片的型号中获得，但每一个系列不一定相同。 <br />1)TMS320C2000系列： <br />TMS320F206－最高主频20MHz。 <br />TMS320C203/C206－最高主频40MHz。 <br />TMS320F24x－最高主频20MHz。 <br />TMS320LF24xx－最高主频30MHz。 <br />TMS320LF24xxA－最高主频40MHz。 <br />TMS320LF28xx－最高主频150MHz。 <br />2)TMS320C3x系列： <br />TMS320C30：最高主频25MHz。 <br />TMS320C31PQL80：最高主频40MHz。 <br />TMS320C32PCM60：最高主频30MHz。 <br />TMS320VC33PGE150：最高主频75MHz。 <br />3)TMS320C5000系列： <br />TMS320VC54xx：最高主频160MHz。 <br />TMS320VC55xx：最高主频300MHz。 <br />4)TMS320C6000系列： <br />TMS320C62xx：最高主频300MHz。 <br />TMS320C67xx：最高主频230MHz。 <br />TMS320C64xx：最高主频720MHz。 <br /><br />十一.DSP可以降频使用吗？<br />可以，DSP的主频均有一定的工作范围，因此DSP均可以降频使用。 <br /><br />十二.如何选择外部时钟？<br />DSP的内部指令周期较高，外部晶振的主频不够，因此DSP大多数片内均有PLL。但每个系列不尽相同。 <br />1)TMS320C2000系列： <br />TMS320C20x：PLL可以÷2，×1，×2和×4，因此外部时钟可以为5MHz－40MHz。 <br />TMS320F240：PLL可以÷2，×1，×1.5，×2，×2.5，×3，×4，×4.5，×5和×9，因此外部时钟可以为2.22MHz－40MHz。 <br />TMS320F241/C242/F243：PLL可以×4，因此外部时钟为5MHz。 TMS320LF24xx：PLL可以由RC调节，因此外部时钟为4MHz－20MHz。 <br />TMS320LF24xxA：PLL可以由RC调节，因此外部时钟为4MHz－20MHz。 <br />2)TMS320C3x系列： <br />TMS320C3x：没有PLL，因此外部主频为工作频率的2倍。 <br />TMS320VC33：PLL可以÷2，×1，×5，因此外部主频可以为12MHz－100MHz。 <br />3)TMS320C5000系列： <br />TMS320VC54xx：PLL可以÷4，÷2，×1-32，因此外部主频可以为0.625MHz－50MHz。 <br />TMS320VC55xx：PLL可以÷4，÷2，×1-32，因此外部主频可以为6.25MHz－300MHz。 <br />4)TMS320C6000系列： <br />TMS320C62xx：PLL可以×1，×4，×6，×7，×8，×9，×10和×11，因此外部主频可以为11.8MHz－300MHz。 <br />TMS320C67xx：PLL可以×1和×4，因此外部主频可以为12.5MHz－230MHz。 <br />TMS320C64xx：PLL可以×1，×6和×12，因此外部主频可以为30MHz－720MHz<br /><br />十三.如何选择DSP的外部存储器？<br />DSP的速度较快，为了保证DSP的运行速度，外部存储器需要具有一定的速度，否则DSP访问外部存储器时需要加入等待周期。 <br />1)对于C2000系列： C2000系列只能同异步的存储器直接相接。 C2000系列的DSP目前的最高速度为150MHz。建议可以用的存储器有： <br />CY7C199-15：32K×8，15ns，5V； <br />CY7C1021-12：64K×16，15ns，5V； CY7C1021V33-12：64K×16，15ns，3.3V。 <br />2)对于C3x系列： C3x系列只能同异步的存储器直接相接。 C3x系列的DSP的最高速度，5V的为40MHz，3.3V的为75MHz，为保证DSP无等待运行，分别需要外部存储器的速度&lt;25ns和&lt;12ns。建议可以用的存储器有： <br />ROM： AM29F400-70：256K×16，70ns，5V，加入一个等待； <br />AM29LV400-55(SST39VF400)：256K×16，55ns，3.3V，加入两个等待（目前没有更快的Flash）。 <br />SRAM： CY7C199-15：32K×8，15ns，5V； <br />CY7C1021-15：64K×16，15ns，5V； <br />CY7C1009-15：128K×8，15ns，5V； <br />CY7C1049-15：512K×8，15ns，5V； <br />CY7C1021V33-15：64K×16，15ns，3.3V； <br />CY7C1009V33-15：128K×8，15ns，3.3V； <br />CY7C1041V33-15：256k×16，15ns，3.3V。 <br />3)对于C54x系列： C54x系列只能同异步的存储器直接相接。 C54x系列的DSP的速度为100MHz或160MHz，为保证DSP无等待运行，需要外部存储器的速度&lt;10ns或&lt;6ns。建议可以用的存储器有： <br />ROM： AM29LV400-55(SST39VF400)：256K×16，55ns，3.3V，加入5或9个等待（目前没有更快的Flash）。 <br />SRAM： CY7C1021V33-12：64K×16，12ns，3.3V，加入一个等待； <br />CY7C1009V33-12：128K×8，12ns，3.3V，加入一个等待。 <br />4)对于C55x和C6000系列： TI的DSP中只有C55x和C6000可以同同步的存储器相连，同步存储器可以保证系统的数据交换效率更高。 <br />ROM： AM29LV400-55(SST39VF400)：256K×16，55ns，3.3V。 <br />SDRAM： HY57V651620BTC-10S：64M，10ns。 <br />SBSRAM： CY7C1329-133AC，64k×32； <br />CY7C1339-133AC，128k×32。 <br />FIFO：CY7C42x5V-10ASC，32k/64k×18。 <br /><br />十四.DSP芯片有多大的驱动能力？<br />DSP的驱动能力较强，可以不加驱动，连接8个以上标准TTL门。 <br /><br />十五.调试TMS320C2000系列的常见问题？<br />1)单步可以运行，连续运行时总回0地址： Watchdog没有关，连续运行复位DSP回到0地址。 <br />2)OUT文件不能load到片内flash中： Flash不是RAM，不能用简单的写指令写入，需要专门的程序写入。CCS和C Source Debugger中的load命令，不能对flash写入。 OUT文件只能load到片内RAM，或片外RAM中。 <br />3)在flash中如何加入断点： 在flash中可以用单步调试，也可以用硬件断点的方法在flash中加入断点，软件断点是不能加在ROM中的。硬件断点，设置存储器的地址，当访问该地址时产生中断。 <br />4)中断向量： C2000的中断向量不可重定位，因此中断向量必须放在0地址开始的flash内。在调试系统时，代码放在RAM中，中断向量也必须放在flash内。 <br /><br />十六.调试TMS320C3x系列的常见问题？<br />1)TMS320C32的存储器配置： TMS320C32的程序存储器可以配置为16位或32位；数据存储器可以配置为8位、16位或32位。 <br />2)TMS320VC33的PLL控制： TMS320VC33的PLL控制端只能接1.8V，不能接3.3V或5V。 <br /><br />十七.如何调试多片DSP？<br />对
于有MPSD仿真口的DSP（TMS320C30/C31/C32），不能用一套仿真器同时调试，每次只能调试其中的一个DSP；
对于有JTAG仿真口的DSP，可以将JTAG串接在一起，用一套仿真器同时调试多个DSP，每个DSP可以用不同的名字，在不同的窗口中调试。
注意：如果在JTAG和DSP间加入驱动，一定要用快速的门电路，不能使用如LS的慢速门电路。 <br /><br />十八.在DSP系统中为什么要使用CPLD？<br />DSP
的速度较快，要求译码的速度也必须较快。利用小规模逻辑器件译码的方式，已不能满足DSP系统的要求。
同时，DSP系统中也经常需要外部快速部件的配合，这些部件往往是专门的电路，有可编程器件实现。
CPLD的时序严格，速度较快，可编程性好，非常适合于实现译码和专门电路。 <br /><br />十九.DSP系统构成的常用芯片有哪些？<br />1)电源： TPS73HD3xx，TPS7333，TPS56100，PT64xx... <br />2)Flash： AM29F400，AM29LV400，SST39VF400... <br />3)SRAM： CY7C1021，CY7C1009，CY7C1049... <br />4)FIF CY7C425，CY7C42x5... <br />5)Dual port： CY7C136，CY7C133，CY7C1342... <br />6)SBSRAM： CY7C1329，CY7C1339... <br />7)SDRAM： HY57V651620BTC... <br />8)CPLD： CY37000系列，CY38000系列，CY39000系列... <br />9)PCI： PCI2040，CY7C09449... <br />10)USB： AN21xx，CY7C68xxx... <br />11)Codec：TLV320AIC23，TLV320AIC10... <br />12)A/D,D/A：ADS7805，TLV2543... <br />具体资料见www.ti.com，www.cypress.com <br /><br />二十.什么是boot loader？<br />DSP
的速度尽快，EPROM或flash的速度较慢，而DSP片内的RAM很快，片外的RAM也较快。为了使DSP充分发挥它的能力，必须将程序代码放在
RAM中运行。为了方便的将代码从ROM中搬到RAM中，在不带flash的DSP中，TI在出厂时固化了一段程序，在上电后完成从ROM或外设将代码搬
到用户指定的RAM中。此段程序称为"boot loader"。 <br /><br />二十一.TMS320C3x如何boot？<br />在MC/MP管脚为高时，C3x进入boot状态。C3x的boot loader在reset时，判断外部中断管脚的电平。根据中断配置决定boot的方式为存储器加载还是串口加载，其中ROM的地址可以为三个中的一个，ROM可以为8位。 <br /><br />二十二.Boot有问题如何解决？<br />1)仔细检查boot的控制字是否正确。 <br />2)仔细检查外部管脚设置是否正确。 <br />3)仔细检查hex文件是否转换正确。 <br />4)用仿真器跟踪boot过程，分析错误原因。 <br /><br />二十三.DSP为什么要初始化？<br />DSP在RESET后，许多的寄存器的初值一般同用户的要求不一致，例如：等待寄存器，SP，中断定位寄存器等，需要通过初始化程序设置为用户要求的数值。 初始化程序的主要作用： 1)设置寄存器初值。 2)建立中断向量表。 3)外围部件初始化。 <br /><br />二十四.DSP有哪些数学库及其它应用软件？<br />TI公司为了方便客户开发DSP，在它的网站上提供了许多程序的示例和应用程序，如MATH库，FFT，FIR/IIR等，可以在TI的网页免费下载。 <br /><br />二十五.如何获得DSP专用算法？<br />TI有许多的Third Party可以通过DSP上的多种算法软件。可以通过TI的网页搜索你所需的算法，找到通过算法的公司，同相应的公司联系。注意这些算法都是要付费的。<br /><br />二十六.eXpressDSP是什么？<br />eXpressDSP
是一种实时DSP软件技术，它是一种DSP编程的标准，利用它可以加快你开发DSP软件的速度。
以往DSP软件的开发没有任何标准，不同的人写的程序一般无法连接在一起。DSP软件的调试工具也非常不方便。使得DSP软件的开发往往滞后于硬件的开
发。 eXpressDSP集成了CCS(Code Composer Studio)开发平台，DSP
BIOS实时软件平台，DSP算法标准和第三方支持四部分。利用该技术，可以使你的软件调试，软件进程管理，软件的互通及算法的获得，都便的容易。这样就
可以加快你的软件开发进程。 <br />1)CCS是eXpressDSP的基础，因此你必须首先拥有CCS软件。 <br />2)DSP BIOS是eXpressDSP的基本平台，你必须学会所有DSP BIOS。 <br />3)DSP算法标准可以保证你的程序可以方便的同其它利用eXpressDSP技术的程序连接在一起。同时也保证你的程序的延续性。 <br /><br />二十七.为什么要用DSP？<br />3G
技术和internate的发展，要求处理器的速度越来越高，体积越来越小，DSP的发展正好能满足这一发展的要求。因为，传统的其它处理器都有不同的缺
陷。MCU的速度较慢；CPU体积较大，功耗较高；嵌入CPU的成本较高。
DSP的发展，使得在许多速度要求较高，算法较复杂的场合，取代MCU或其它处理器，而成本有可能更低。 <br /><br />二十八.如何选择DSP？<br />选择DSP可以根据以下几方面决定： <br />1)速度： DSP速度一般用MIPS或FLOPS表示，即百万次/秒钟。根据您对处理速度的要求选择适合的器件。一般选择处理速度不要过高，速度高的DSP，系统实现也较困难。 <br />2)精度： DSP芯片分为定点、浮点处理器，对于运算精度要求很高的处理，可选择浮点处理器。定点处理器也可完成浮点运算，但精度和速度会有影响。 <br />3)寻址空间： 不同系列DSP程序、数据、I/O空间大小不一，与普通MCU不同，DSP在一个指令周期内能完成多个操作，所以DSP的指令效率很高，程序空间一般不会有问题，关键是数据空间是否满足。数据空间的大小可以通过DMA的帮助，借助程序空间扩大。 <br />4)成本： 一般定点DSP的成本会比浮点DSP的要低，速度也较快。要获得低成本的DSP系统，尽量用定点算法，用定点DSP。 <br />5)实现方便： 浮点DSP的结构实现DSP系统较容易，不用考虑寻址空间的问题，指令对C语言支持的效率也较高。 <br />6)内部部件：根据应用要求，选择具有特殊部件的DSP。如：C2000适合于电机控制；OMAP适合于多媒体等。 <br /><br />二十九.DSP同MCU相比的特点？<br />1)DSP的速度比MCU快，主频较高。 <br />2)DSP适合于数据处理，数据处理的指令效率较高。 <br />3)DSP均为16位以上的处理器，不适合于低档的场合。 <br />4)DSP可以同时处理的事件较多，系统级成本有可能较低。 <br />5)DSP的灵活性较好，大多数算法都可以软件实现。 <br />6)DSP的集成度较高，可靠性较好。 <br /><br />三十.DSP同嵌入CPU相比的特点？<br />1)DSP是单片机，构成系统简单。 2)DSP的速度快。 3)DSP的成本较低。 4)DSP的性能高，可以处理较多的任务。 <br /><br />三十一.如何编写C2000片内Flash？<br />DSP中的Flash的编写方法有三中： <br />1.
通过仿真器编写：在我们的网页上有相关的软件，在销售仿真器时我们也提供相关软件。其中LF240x的编写可以在CCS中加入一个插件，F24x的编写需
要在windows98下的DOS窗中进行。具体步骤见软件中的readme。有几点需要注意： a.必须为MC方式；
b.F206的工作频率必须为20MHz； c.F240需要根据PLL修改C240_CFG.I文件。建议外部时钟为20MHz。
d.LF240x也需要根据PLL修改文件。 d.如果编写有问题，可以用BFLWx.BAT修复。 <br />2.提供串口编写：TI的网页上有相关软件。注意只能编写一次，因为编写程序会破坏串口通信程序。 <br />3.在你的程序中编写：TI的网页上有相关资料。 <br /><br />三十二.如何编写DSP外部的Flash？<br />DSP的外部Flash编写方法： <br />1.通过编程器编写：将OUT文件通过HEX转换程序转换为编程器可以接受的格式，再由编程器编写。 <br />2.通过DSP软件编写：您需要根据Flash的说明，编写Flash的编写程序，将应用程序和编写Flash的程序分别load到RAM中，运行编写程序编写。 <br /><br />三十三.对于C5000，大于48K的程序如何BOOT？<br />对于C5000，片内的BOOT程序在上电后将数据区的内容，搬移到程序区的RAM中，因此FLASH必须在RESET后放在数据区。由于C5000，数据区的空间有限，一次BOOT的程序不能对于48K。解决的方法如下： <br />1.在RESET后，将FLASH译码在数据区，RAM放在程序区，片内BOOT程序将程序BOOT到RAM中。 <br />2.用户初试化程序发出一个I/O命令（如XF），将FLASH译码到程序区的高地址。开放数据区用于其它的RAM。 <br />3.用户初试化程序中包括第二次BOOT程序（此程序必须用户自己编写），将FLASH中没有BOOT的其它代码搬移到RAM中。 <br />4.开始运行用户处理程序。 <br /><br />三十四.DSP外接存储器的控制方式<br />对于一般的存储器具有RD、WR和CS等控制信号，许多DSP（C3x、C5000）都没有控制信号直接连接存储器，一般采用的方式如下： <br />1.CS有地址线和PS、DS或STRB译码产生； <br />2./RD=/STRB+/R/W； 3./WR=/STRB+R/W。<br /><br />三十五.GEL文件的功能？<br />GEL文件的功能同emuinit.cmd的功能基本相同，用于初始化DSP。但它的功能比emuinit的功能有所增强，GEL在CCS下有一个菜单，可以根据DSP的对象不同，设置不同的初始化程序。以TMS320LF2407为例： <br />#define SCSR1 0x7018 ；定义scsr1寄存器 <br />#define SCSR2 0X7019 ；定义scsr2寄存器 <br />#define WDKEY 0x7025 ；定义wdkey寄存器 <br />#define WDNTR 0x7029 ；定义wdntr寄存器 <br />StartUp() ; 开始函数 <br />{ <br />GEL_MapReset(); ; 存储空间复位 GEL_MapAdd(0x0000,0,0x7fff,1,1); 定义程序空间从0000－7fff 可读写 <br />GEL_MapAdd(0x8000,0,0x7000,1,1); 定义程序空间从8000－f000 可读写 <br />GEL_MapAdd(0x0000,1,0x10000,1,1); 定义数据空间从0000－10000可读写 <br />GEL_MapAdd(0xffff,2,1,1,1); 定义i/o 空间0xffff可读写 <br />GEL_MapOn(); 存储空间打开 <br />GEL_MemoryFill(0xffff,2,1,0x40); 在i/o空间添入数值40h <br />*(int *)SCSR1=0x0200; 给scsr1寄存器赋值 <br />*(int *)SCSR2=0x000C; 给scsr2寄存器赋值，在这里可以进行mp/mc方式的转换 <br />*(int *)WDNTR=0x006f; 给wdntr寄存器赋值 <br />*(int *)WDKEY=0x055; 给wdkey寄存器赋值 <br />*(int *)WDKEY=0x0AA; 给wdkey寄存器赋值 <br />} <br /><br />三十六.使用TI公司模拟器件与DSP结合使用的好处。<br />1)在使用TI公司的DSP的同时，使用TI公司的模拟可以和DSP进行无缝连接。器件与器件之间不需要任何的连接或转接器件。这样即减少了板卡的尺寸，也降低了开发难度。 <br />2)同为TI公司的产品，很多器件可以固定搭配使用。少了器件选型的烦恼 <br />3)TI在CCS中提供插件，可以用于DSP和模拟器件的开发，非常方便。 <br /><br />三十七.C语言中可以嵌套汇编语言？<br />可以。在ANSI C标准中的标准用法就是用C语言编写主程序，用汇编语言编写子程序，中断服务程序，一些算法，然后用C语言调用这些汇编程序，这样效率会相对比较高<br /><br />三十八.在定点DSP系统中可否实现浮点运算？<br />当然可以，因为DSP都可以用C,只要是可以使用c语言的场合都可以实现浮点运算。<br /><br />三十九.JTAG头的使用会遇到哪些情况？<br />1)DSP的CLKOUT没有输出，工作不正常。 <br />2)Emu0，Emu1需要上拉。 <br />3)TCK的频率应该为10M。 <br />4)在3.3V DSP中，PD脚为3.3V 供电，但是仿真器上需要5V电压供电，所以PP仿真器盒上需要单独供电。 <br />4)仿真多片DSP。在使用菊花链的时候，第一片DSP的TDO接到第二片DSP的TDI即可。注意当串联DSP比较多的时候，信号线要适当的增加驱动。 <br /><br />四十.include头文件（.h)的主要作用<br />头文件，一般用于定义程序中的函数、参数、变量和一些宏单元，同库函数配合使用。因此，在使用库时，必须用相应的头文件说明。 <br /><br />四十一.DSP中断向量的位置<br />1)2000系列dsp的中断向量只能从0000H处开始。所以在我们调试程序的时候，要把DSP选择为MP（微处理器方式），把片内的Flash屏蔽掉，免去每次更改程序都要重新烧写Flash工作。 <br />2)3x系列dsp的中断向量也只能在固定的地址。 <br />3)5000，6000系列dsp的中断向量可以重新定位。但是它只能被重新定位到Page0范围内的任何空间。<br /><br />四十二.有源晶振与晶体的区别，应用范围及用法<br />1)晶体需要用DSP片内的振荡器，在datasheet上有建议的连接方法。晶体没有电压的问题，可以适应于任何DSP，建议用晶体。 <br />2)有源晶振不需要DSP的内部振荡器，信号比较稳定。有源晶振用法：一脚悬空，二脚接地，三脚接输出，四脚接电压。 <br /><br />四十三.程序经常跑飞的原因<br />1)程序没有结尾或不是循环的程序。 <br />2)nmi管脚没有上拉。 <br />3)在看门狗动作的时候程序会经常跑飞。 <br />4)程序编制不当也会引起程序跑飞。 <br />5)硬件系统有问题。 <br /><br />四十四.并行FLASH引导的一点经验<br />最
近BBS上关于FLASH和BOOT的讨论很活跃，我也多次来此请教。前几天自制的DSP板引导成功，早就打算写写这方面的东西。我用的DSP是
5416，以其为核心，做了一个相对独立的子系统（硬件、软件、算法），目前都已基本做好。
下面把在FLASH引导方面做的工作向大家汇报一下，希望能对大家有所帮助。本人经验和文笔都有限，写的不好请大家谅解。 <br />硬件环境： <br />DSP：TMS320VC5416PGE160 <br />FLASH：SST39VF400A-70-4C-EK 都是贴片的，FLASH映射在DSP数据空间的0x8000-0xFFFF <br />软件环境： CCS v2.12.01 <br />主
程序（要烧入FLASH的程序）：
DEBUG版，程序占用空间0x28000-0x2FFFF（片内SARAM），中断向量表在0x0080-0x00FF（片内DARAM），数据空间使
用0x0100-0x7FFF（片内DARAM）。
因为FLASH是贴片的，所以需要自己编一个数据搬移程序，把要主程序搬移到FLASH中。在写入FLASH数据时，还应写入引导表的格式数据。最后在数
据空间的0xFFFF处写入引导表的起始地址（这里为0x8000）。 <br />搬移程序：
DEBUG版，程序空间0x38000-0x3FFFF（片内SARAM），中断向量表在0x7800-0x78FF（片内DARAM），数据空间使用
0x5000-0x77FF（片内DARAM）。 搬移程序不能使用与主程序的程序空间和中断向量表重合的物理空间，以免覆盖。
烧写时，同时打开主程序和搬移程序的PROJECT，先LOAD主程序，再LOAD搬移程序，然后执行搬移程序，烧写OK! 附：搬移程序（仅供参考）
<br />volatile unsigned int *pTemp=(unsigned int *)0x7e00; unsigned int iFlashAddr; <br />int iLoop; /* 在引导表头存放并行引导关键字 */ <br />iFlashAddr=0x8000; <br />WriteFlash(iFlashAddr,0x10aa); <br />iFlashAddr++; /* 初始化SWWSR值 */ <br />WriteFlash(iFlashAddr,0x7e00); <br />iFlashAddr++; /* 初始化BSCR值 */ <br />WriteFlash(iFlashAddr,0x8006); <br />iFlashAddr++; /* 程序执行的入口地址 */ <br />WriteFlash(iFlashAddr,0x0002); <br />iFlashAddr++; <br />WriteFlash(iFlashAddr,0x8085); <br />iFlashAddr++; /* 程序长度 */ <br />WriteFlash(iFlashAddr,0x7f00); <br />iFlashAddr++; /* 程序要装载到的地址 */ <br />WriteFlash(iFlashAddr,0x0002); <br />iFlashAddr++; <br />WriteFlash(iFlashAddr,0x8000); <br />iFlashAddr++; <br />for (iLoop=0;iLoop&lt;0x7f00;iLoop++) <br />{ /* 从程序空间读数据，放到暂存单元 */ <br />asm(" pshm al"); <br />asm(" pshm ah"); <br />asm(" rsbx cpl"); <br />asm(" ld #00fch,dp"); <br />asm(" stm #0000h, ah"); <br />asm(" MVDM _iLoop, al"); <br />asm(" add #2800h,4,a"); <br />asm(" reada 0h"); <br />asm(" popm ah"); <br />asm(" popm al"); <br />asm(" ssbx cpl"); /* 把暂存单元内容写入FLASH */ <br />WriteFlash(iFlashAddr,*pTemp); <br />iFlashAddr++; } /* 中断向量表长度 */ <br />WriteFlash(iFlashAddr,0x0080); <br />iFlashAddr++; /* 中断向量表装载地址 */ <br />WriteFlash(iFlashAddr,0x0000); <br />iFlashAddr++; <br />WriteFlash(iFlashAddr,0x0080); <br />iFlashAddr++; <br />for (iLoop=0;iLoop&lt;0x0080;iLoop++) { /* 从程序空间读数据，放到暂存单元 */ <br />asm(" pshm al"); <br />asm(" pshm ah"); <br />asm(" rsbx cpl"); <br />asm(" ld #00fch,dp"); <br />asm(" stm #0000h, ah"); <br />asm(" MVDM _iLoop, al"); <br />asm(" add #0080h,0,a"); <br />asm(" reada 0h"); <br />asm(" popm ah"); <br />asm(" popm al"); <br />asm(" ssbx cpl"); /* 把暂存单元内容写入FLASH */ <br />WriteFlash(iFlashAddr,*pTemp); <br />iFlashAddr++; <br />} /* 写入引导表结束标志 */ <br />WriteFlash(iFlashAddr,0x0000); <br />iFlashAddr++; <br />WriteFlash(iFlashAddr,0x0000); /* 在数据空间的0xFFFF写入引导表起始地址 */ <br />iFlashAddr=0xffff; <br />WriteFlash(iFlashAddr,0x8000); <br /><br />四十五.关于LF2407A的FLASH烧写问题的几点说明<br />TI
现在关于LF24x写入FLASH的工具最新为c2000flashprogsw_v112。可以支持LF2407、LF2407a、LF2401及相关
的LF240x系列。建议使用此版本。在http://focus.ti.com/docs/tool/toolf...灿写松招闯绦颉?/a&gt;
在使用这个工具时注意： <br />一,先解压，再执行setup.exe。 <br />二、进入cc中，在tools图标下有烧写工具； <br />1、关
于FLASH时钟的选择，此烧写工具默认最高频率进行FLASH的操作。根据目标系统的工作主频重新要进行PLL设置。方法：先在advance
options下面的View Config
file中修改倍频。存盘后，在相应的目录下（tic2xx\\algos\\相应目录）运行buildall.bat就可以完成修改了。再进行相应的操
作即可。 <br />2、若是你所选的频率不是最高频率，还需要设定你自已的timings.xx来代替系统默认的最高频率的timings.xx。例如
LF2407a的默认文件是timings.40。Timings.xx可以利用include\\timings.xls的excel工作表来生成。然
后在advance options下面的View Config
file中修改相应的位置。存盘后，在相应的目录下运行buildall.bat就可以完成修改了。 <br />3、对于TMS320LF240XA系
列，还要注意：由于这些DSP的FLASH具有加密功能，加密地址为程序空间的0x40-0X43H，程序禁止写入此空间，如果写了，此空间的数据被认为
是加密位，断电后进入保护FLASH状态，使FLASH不可重新操作，从而使DSP报废，烧写完毕后一定要进行Program
passwords的操作，如果不做加密操作就默认最后一次写入加密位的数据作为密码。 <br />4、2407A不能用DOS下的烧写软件烧写，必须用c2000flashprogsw_v112软件烧写； <br />5、建议如下： <br />1)、一般调试时，在RAM中进行； <br />2)、程序烧写时，避开程序空间0x40-0x43H加密区，程序最好小于32k； <br />3)、
每次程序烧写完后，将word0，word1,word2，word3分别输入自己的密码，再点击 Program
password，如果加密成功，提示Program is
arrayed，如果0x40－0x43h中写入的是ffff，认为处于调试状态，flash不会加密； <br />4)、断电后，下次重新烧写时需要往word0～word3输入已设的密码，再unlock，成功后可以重新烧写了； <br />6、VCPP管脚接在＋5V上，是应直接接的，中间不要加电阻。 <br />7、具体事宜请阅读相应目录下的readme1,readme2帮助文件。 <br />8.注意*.cmd文件的编写时应该避开40-43H单元，好多客户由于没有注意到这里而把FALSH加密。 <br /><br />四十六.如何设置硬件断点？<br />在profiler －&gt;profile point -&gt; break point <br /><br />四十七.c54x的外部中断是电平响应还是沿响应？<br />是沿响应，准确的说，它要检测到100(一个clk的高和两个clk的低)的变化才可以。<br /><br />四十八。参考程序，里面好象都要 disable wachdog,不知道为什么?<br />watchdog是一个计数器，溢出时会复位你的DSP，不disable的话，你的系统会动不动就reset。<br />四十九。DSP系统设计100问<br />一、时钟和电源<br />问：DSP的电源设计和时钟设计应该特别注意哪些方面？外接晶振选用有源的好还是无源的好？<br />答：时钟一般使用晶体，电源可用TI的配套电源。外接晶振用无源的好。<br />问：TMS320LF2407的A/D转换精度保证措施。<br />答：参考电源和模拟电源要求干净。<br />问：系统调试时发现纹波太大，主要是哪方面的问题？<br />答：如果是电源纹波大，加大电容滤波。<br />问：请问我用5V供电的有源晶振为DSP提供时钟，是否可以将其用两个电阻进行分压后再接到DSP的时钟输入端，这样做的话，时钟工作是否稳定？<br />答：这样做不好，建议使用晶体。<br />问：一个多DSP电路板的时钟，如何选择比较好？DSP电路板的硬件设计和系统调试时的时序问题？<br />答：建议使用时钟芯片，以保证同步。硬件设计要根据DSP芯片的时序，选择外围芯片，根据时序设定等待和硬件逻辑。<br />二．干扰与板的布局<br />问：器件布局应重点考虑哪些因素？例如在集中抄表系统中？<br />答：可用TMS320VC5402，成本不是很高。器件布局重点应是存贮器与DSP的接口。<br />问：在设计DSP的PCB板时应注意哪些问题？<br />答：1.电源的布置；2.时钟的布置；3.电容的布置；4.终端电路；5.数字同模拟的布置。<br />问：请问DSP在与前向通道(比如说AD)接口的时候，布线过程中要注意哪些问题，以保证AD采样的稳定性？<br />答：模拟地和数字地分开，但在一点接地。<br />问：DSP主板设计的一般步骤是什么？需要特别注意的问题有哪些？<br />答：1.选择芯片；2.设计时序；3.设计PCB。最重要的是时序和布线。<br />问：在硬件设计阶段如何消除信号干扰（包括模拟信号及高频信号）？应该从那些方面着<br />手？<br />答：1.模拟和数字分开；2.多层板；3.电容滤波。<br />问：在电路板的设计上，如何很好的解决静电干扰问题。<br />答：一般情况下，机壳接大地，即能满足要求。特殊情况下，电源输入、数字量输入串接<br />专用的防静电器件。<br />问：DSP板的电磁兼容（EMC）设计应特别注意哪些问题?<br />答：正确处理电源、地平面，高速的、关键的信号在源端串接端接电阻，避免信号反射。<br />问：用电感来隔离模拟电源和数字电源，其电感量如何决定？是由供电电流或噪音要求来<br />决定吗？有没有计算公式？<br />答：电感或磁珠相当于一个低通滤波器，直流电源可以通过，而高频噪声被滤除。所以电<br />感的选择主要决定于电源中高频噪声的成分。<br />问：讲座上的材料多是电源干扰问题，能否介绍板上高频信号布局（Layout）时要注意的<br />问题以及数字信号对模拟信号的影响问题？<br />答：数字信号对模拟信号的干扰主要是串扰，在布局时模拟器件应尽量远离高速数字器件，高速数字信号尽量远离模拟部分，并且应保证它们不穿越模拟地平面。<br />问：能否介绍PCB布线对模拟信号失真和串音的影响，如何降低和克服？<br />答：有2个方面，1. 模拟信号与模拟信号之间的干扰：布线时模拟信号尽量走粗一些，如果有条件，2个模拟信号之间用地线间隔。2. 数字信号对模拟信号的干扰：数字信号尽量远离模拟信号，数字信号不能穿越模拟地。<br />三．DSP性能<br />问：1.我要设计生物图像处理系统，选用那种型号较好（高性能和低价格）？2.如果选定<br />TI DSP，需要什么开发工具？<br />答：1.你可采用C54x 或 C55x平台，如果你需要更高性能的，可采用C6x系列。2.需要EVM<br />s和XDS510仿真器。<br />问：请介绍一种专门用于快速富利叶变换（FFT）， 数字滤波，卷积，相关等算法的DSP，<br />最好集成12bit以上的ADC功能。<br />答：如果你的系统是马达/能量控制的，我建议你用TMS320LF240x。详情请参阅DSP选择指南：http://www.dspvillage.ti.com/dspguide。<br />问：有些资料说DSP比单片机好，但单片机用的比DSP广。请问这两个在使用上有何区别？<br />答：单片机一般用于要求低的场合，如4/8位的单片机。DSP适合于要求较高的场合。<br />问：我想了解在信号处理方面DSP比FPGA的优点。<br />答：DSP是通用的信号处理器，用软件实现数据处理；FPGA用硬件实现数据处理。DSP的成本便宜，算法灵活，功能强；FPGA的实时性好，成本较高。<br />问：请问减小电路功耗的主要途径有哪些？<br />答：1.选择低功耗的芯片；2.减少芯片的数量；3.尽量使用IDLE。<br />问：用C55设计一个低功耗图像压缩/解压和无线传输的产品，同时双向传输遥控指令和其<br />他信息，要求图像30帧/秒，TFT显示320*240，不知道能否实现？若能，怎样确定性能？选择周边元器件？确定最小的传输速率？能否提供开发的解决方案？软件核？<br />答：1.有可能，要看你的算法。2.建议先在模拟器上模拟。<br />问：用DSP开发MP3，比较专用MP3解码芯片如何，比如成本、难度、周期？谢谢。<br />答：1.DSP的功能强，可以实现附加的功能，如ebook等；2.DSP的性能价格比高；3.难度较大，需要算法，因此周期较长，但TI有现成的方案。<br />问：用DSP开发的系统跟用普通单片机开发的系统相比，有何优势？DSP一般适用于开发什么样的系统？其开发周期、资金投入、开发成本如何？与DSP的接口电路是否还得用专门的芯片？<br />答：1.性能高；2.适合于速度要求高的场合；3.开发周期一般6个月，投入一般要一万元左<br />右；4.不一定，但需要速度较高的芯片。<br />问：DSP会对原来的模拟电路产生什么样的影响？<br />答：一方面DSP用数字处理的方法可以代替原来用模拟电路实现的一些功能；另一方面，DSP的高速性对模拟电路产生较大的干扰，设计时应尽量使DSP远离模拟电路部分。<br />问：请问支持MPEG-4芯片型号是什么？<br />答：C55x或 C6000 或DSC2x<br />问：DSP内的计算速度是快的，但是它的I/O口的交换速度有多快呢？<br />答：主频的1/4左右。<br />四．技术性问题<br />问：我有二个关于C2000的问题：1、C240或C2407的RS复位引脚既可输入，也可输出，直接用CMOS门电路（如74ACT04）驱动是否合适，还是应该用OC门（集电极开路）驱动？2、大程序有时运行异常，但加一两条空指令就正常，是何原因？<br />答：1、OC门（集电极开路）驱动。2、是流水线的问题。<br />问：1.DSP芯片内是否有单个的随机函数指令？2．DSP内的计算速度是快的，但是它的I/O<br />口的交换速度有多快呢？SP如何配合EPLD或FPGA工作呢？<br />答：1.没有。2.取决于你所用的I/O。对于HPI，传输速率（字节）大约为CPU的1/4，对McBSP，位速率（kbps）大约为CPU的1/2。3.你可以级联仿真接口和一个EPLD/FPGA在一起。请参考下面的应用手册： <a href="http://www.ti.com/sc/docs/psheets/abstract/apps/spra439a.htm" target="_blank" class="ilink">http://www.ti.com/sc/docs/psheets/abstract/apps/spra439a.htm</a><br />问：设计DSP系统时，我用C6000系列。DSP引脚的要上拉，或者下拉的原则是怎样的？我经常在设计时为某一管脚是否要设置上/下拉电阻而犹豫不定。<br />答：C6000系列的输入引脚内部一般都有弱的上拉或者下拉电阻，一般不需要考虑外部加上<br />拉或者下拉电阻，特殊情况根据需要配置。<br />问：我正在使用TMS320VC5402，通过HPI下载代码，但C5402的内部只提供16K字的存储区，请问我能通过HPI把代码下载到它的外部扩展存储区运行吗？<br />答：不行，只能下载到片内。<br />问：电路中用到DSP，有时当复位信号为低时，电压也属于正常范围，但DSP加载程序不成功。电流也偏大，有时时钟也有输出。不知为什么？<br />答：复位时无法加载程序。<br />问：DSP和单片机相连组成主从系统时，需要注意哪些问题？<br />答：建议使用HPI接口，或者通过DPRAM连接。<br />问：原来的DSP的程序需放在EPROM中，但EPROM的速度难以和DSP匹配。现在是如何解决此问题的？<br />答：用BootLoad方法解决。<br />问：
我在使用5402DSK时，一上电，不接MIC，只接耳机，不运行任何程序，耳机中有比较明显的一定频率的噪声出现。有时上电后没有出现，但接MIC，运
行范例中的CODEC程序时，又会出现这种噪声。上述情况通常都在DSK工作一段时间后自动消失。我在DSP论坛上发现别人用DSK时也碰到过这种情况，
我自己参照5402DSK做了一块板，所用器件基本一样，也是这现象，请问怎么回事？如何解决？<br />答：开始时没有有效的程序代码，所以上电后是随机状态，出现这种情况是正常的。<br />问：我使用的是TMS320LF2407，但是仿真时不能保证每次都能GO MAIN。我想详细咨询一下，CMD文件的设置用法，还有VECTOR的定义。<br />答：可能看门狗有问题，关掉看门狗。有关CMD文件配置请参考《汇编语言工具》第二章。<br />问：我设计的TMS320VC5402板子在调试软件时会经常出现存储器错误报告，排除是映射的问题，是不是板子不稳定的因素？还是DSP工作不正常的问题？如何判别？<br />答：你可以利用Memoryfill功能，填入一些数值，然后刷新一下，看是不是在变，如果是<br />在变化，则Memory 是有问题。<br />问：如何解决Flash编程的问题:可不可以先用仿真器下载到外程序存储RAM中，然后程序代码将程序代码自己从外程序存储RAM写到F240的内部Flash ROM中，如何写?<br />答：如果你用F240，你可以用下载TI做的工具。其它的可以这样做。<br />问：C5510芯片如何接入E1信号？在接入时有什么需要注意的地方？<br />答：通过McBSP同步串口接入。注意信号电平必须满足要求。<br />问：请问如何通过仿真器把.HEX程序直接烧到FLASH中去?所用DSP为5402是否需要自己另外编写一个烧写程序， 如何实现?谢谢!!<br />答：直接写.OUT。是DSP中写一段程序，把主程序写到FLASH中。<br />问：DSP的硬件设计和其他的电路板有什么不同的地方？<br />答：1.要考虑时序要求；2.要考虑EMI的要求；3.要考虑高速的要求；4.要考虑电源的要求。<br />问：
ADS7811，ADS7815，ADS8320，ADS8325，ADS8341，ADS8343，ADS8344，ADS8345中，哪个可以较方便
地与VC33连接，完成10个模拟信号的AD转换（要求16bit，1毫秒内完成10个信号的采样，当然也要考虑价格）？<br />答：作选择有下列几点需
要考虑1. 总的采样率：1ms、10个通道，总采样率为100K ，所有A/D均能满足要求。2.
A/D与VC33的接口类型：并行、串行。前2种A/D为并行接口，后几种均为串行接口。3.
接口电平的匹配。前2种A/D为5V电平，与VC33不能接口；后几种均可为3.3V电平，可与VC33直接接口。<br />问：DSP的电路板有时调试成功率低于50%，连接和底板均无问题，如何解决？有时DSP同CPLD产生不明原因的冲突，如何避免？<br />答：看来你的硬件设计可能有问题，不应该这么小的成功率。我们的板的成功率为95%以上。<br />问：我们的工程有两人参与开发，由于事先没有考虑周全，一人使用的是助记符方式编写<br />汇编代码，另一人使用的是代数符号方式编写汇编代码，请问CCS5000中这二种编写方式如何嵌在一起调试？<br />答：我没有这样用过，我想可以用下面的办法解决：将一种方式的程序先单独编译为.obj<br />文件，在创建工程时，将这些.obj文件和另一种方式的程序一起加进工程中，二者即可一<br />起编译调试了。<br />问：DSP数据缓冲，能否用SDRAM代替FIFO？<br />答：不行<br />问：ADC或DAC和DSP相连接时，要注意什么问题？比如匹配问题，以保证A/D采样稳定或D/A码不丢失。<br />答：1. 接口方式：并行／串行；2. 接口电平，必须保证二者一致。<br />问：用F240经常发生外部中断丢失现象，甚至在实际环境中只有在程序刚开始时能产生中<br />断，几分钟后就不能产生中断。有时只能采取查询的方式，请问有何有效的解决方法？改<br />为F2407是不是要好些？<br />答：应该同DSP无关。建议你将中断服务程序简化看一下。 <br /><br />四十九.时钟电路选择原则<br />1,系统中要求多个不同频率的时钟信号时，首选可编程时钟芯片; <br />2,单一时钟信号时，选择晶体时钟电路; <br />3,多个同频时钟信号时，选择晶振; <br />4,尽量使用DSP片内的PLL，降低片外时钟频率，提高系统的稳定性; <br />5,C6000、C5510、C5409A、C5416、C5420、C5421和C5441等DSP片内无振荡电路，不能用晶体时钟电路; <br />6,VC5401、VC5402、VC5409和F281x等DSP时钟信号的电平为1.8V，建议采用晶体时钟电路 <br /><br />五十.C程序的代码和数据如何定位<br />1,系统定义: <br />.cinit 存放C程序中的变量初值和常量; <br />.const 存放C程序中的字符常量、浮点常量和用const声明的常量; <br />tch 存放C程序tch语句的跳针表; <br />.text 存放C程序的代码; <br />.bss 为C程序中的全局和静态变量保留存储空间; <br />.far 为C程序中用far声明的全局和静态变量保留空间; <br />.stack 为C程序系统堆栈保留存储空间，用于保存返回地址、函数间的参数传递、存储局部变量和保存中间结果; <br />.sysmem 用于C程序中malloc、calloc和realloc函数动态分配存储空间 <br />2,用户定义: <br />#pragma CODE_SECTION (symbol, "section name"); <br />#pragma DATA_SECTION (symbol, "section name") <br /><br />五十一.cmd文件<br />由3部分组成： <br />1)输入／输出定义：.obj文件：链接器要链接的目标文件;.lib文件：链接器要链接的库文件;.map文件：链接器生成的交叉索引文件;.out文件：链接器生成的可执行代码;链接器选项 <br />2)MEMORY命令：描述系统实际的硬件资源 <br />3)SECTIONS命令：描述"段"如何定位 <br /><br />五十二.为什么要设计CSL?<br />1,DSP片上外设种类及其应用日趋复杂 <br />2,提供一组标准的方法用于访问和控制片上外设 <br />3,免除用户编写配置和控制片上外设所必需的定义和代码 <br /><br />五十三.什么是CSL?<br />1,用于配置、控制和管理DSP片上外设 <br />2,已为C6000和C5000系列DSP设计了各自的CSL库 <br />3,CSL库函数大多数是用C语言编写的，并已对代码的大小和速度进行了优化 <br />4,CSL库是可裁剪的：即只有被使用的CSL模块才会包含进应用程序中 <br />5,CSL库是可扩展的：每个片上外设的API相互独立，增加新的API，对其他片上外设没有影响 <br /><br />五十四.CSL的特点<br />1,片上外设编程的标准协议：定义一组标准的APIs：函数、数据类型、宏; <br />2,对硬件进行抽象，提取符号化的片上外设描述:定义一组宏，用于访问和建立寄存器及其域值 <br />3,基本的资源管理:对多资源的片上外设进行管理; <br />4,已集成到DSP/BIOS中:通过图形用户接口GUI对CSL进行配置; <br />5,使片上外设容易使用:缩短开发时间，增加可移植. <br /><br />五十五.为什么需要电平变换?<br />1)DSP系统中难免存在5V/3.3V混合供电现象; <br />2)I/O为3.3V供电的DSP，其输入信号电平不允许超过电源电压3.3V; <br />3)5V器件输出信号高电平可达4.4V; <br />4)长时间超常工作会损坏DSP器件; <br />5)输出信号电平一般无需变换 <br /><br />五十六.电平变换的方法<br />1,总线收发器（Bus Transceiver）： <br />常用器件： SN74LVTH245A（8位）、SN74LVTH16245A（16位） <br />特点：3.3V供电，需进行方向控制， <br />延迟：3.5ns，驱动：-32/64mA， <br />输入容限：5V <br />应用：数据、地址和控制总线的驱动 <br />2,总线开关（Bustch） <br />常用器件：SN74CBTD3384（10位）、SN74CBTD16210（20位） <br />特点：5V供电，无需方向控制 <br />延迟：0.25ns，驱动能力不增加 <br />应用：适用于信号方向灵活、且负载单一的应用，如McBSP等外设信号的电平变换 <br />3,2选1切换器（1 of 2 Multiplexer） <br />常用器件：SN74CBT3257（4位）、SN74CBT16292（12位） <br />特点：实现2选1，5V供电，无需方向控制 <br />延迟：0.25ns，驱动能力不增加 <br />应用：适用于多路切换信号、且要进行电平变换的应用，如双路复用的McBSP <br />4,CPLD <br />3.3V供电，但输入容限为5V，并且延迟较大：＞7ns，适用于少量的对延迟要求不高的输入信号 <br />5,电阻分压 <br />10KΩ和20KΩ串联分压，5V×20÷（10＋20）≈3.3V <br /><br />五十七.未用的输入／输出引脚的处理<br />1,未用的输入引脚不能悬空不接，而应将它们上拉活下拉为固定的电平 <br />1)关键的控制输入引脚，如Ready、Hold等，应固定接为适当的状态,Ready引脚应固定接为有效状态,Hold引脚应固定接为无效状态 <br />2)无连接（NC）和保留（RSV）引脚,NC 引脚：除非特殊说明，这些引脚悬空不接,RSV引脚：应根据数据手册具体决定接还是不接 <br />3)非关键的输入引脚,将它们上拉或下拉为固定的电平，以降低功耗 <br />2,未用的输出引脚可以悬空不接 <br />3,未用的I/O引脚:如果确省状态为输入引脚，则作为非关键的输入引脚处理，上拉或下拉为固定的电平;如果确省状态为输出引脚，则可以悬空不接<br />二.DSP的C语言同主机C语言的主要区别？<br />1)DSP的C语言是标准的ANSI C，它不包括同外设联系的扩展部分，如屏幕绘图等。但在CCS中，为了方便调试，可以将数据通过prinf命令虚拟输出到主机的屏幕上。 <br />2)DSP的C语言的编译过程为，C编译为ASM，再由ASM编译为OBJ。因此C和ASM的对应关系非常明确，非常便于人工优化。 <br />3)DSP的代码需要绝对定位；主机的C的代码有操作系统定位。 <br />4)DSP的C的效率较高，非常适合于嵌入系统。 <br /><br />三.DSP发展动态<br />1.TMS320C2000
TMS320C2000系列包括C24x和C28x系列。C24x系列建议使用LF24xx系列替代C24x系列，LF24xx系列的价格比C24x便
宜，性能高于C24x，而且LF24xxA具有加密功能。 C28x系列主要用于大存储设备管理，高性能的控制场合。 <br />2.TMS320C3x TMS320C3x系列包括C3x和VC33，主要推荐使用VC33。C3x系列是TI浮点DSP的基础，不可能停产，但价格不会进一步下调。 <br />3.TMS320C5x TMS320C5x系列已不推荐使用，建议使用C24x或C5000系列替代。 <br />4.TMS320C5000
TMS320C5000系列包括C54x和C55x系列。
其中VC54xx还不断有新的器件出现，如：TMS320VC5471（DSP＋ARM7）。
C55x系列是TI的第三代DSP，功耗为VC54xx的1/6，性能为VC54xx的5倍，是一个正在发展的系列。 C5000系列是目前TI
DSP的主流DSP，它涵盖了从低档到中高档的应用领域，目前也是用户最多的系列。 <br />5.TMS320C6000
TMS320C6000系列包括C62xx、C67xx和C64xx。此系列是TI的高档DSP系列。
其中C62xx系列是定点的DSP，系列芯片种类较丰富，是主要的应用系列。 C67xx系列是浮点的DSP，用于需要高速浮点处理的领域。
C64xx系列是新发展，性能是C62xx的10倍。 <br />6.OMAP系列 是TI专门用于多媒体领域的芯片，它是C55＋ARM9，性能卓越，非常适合于手持设备、Internet终端等多媒体应用。 
			</span>
				<br />
				<br />
		</font>
<img src ="http://www.cppblog.com/erran/aggbug/34166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 23:04 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Delphi取整函数</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34152.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 13:34:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34152.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34152.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34152.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34152.html</trackback:ping><description><![CDATA[
		<font face="Arial">floor 和 ceil 是 math unit 里的函数，使用前要先 Uses Math。<br />trunc 和 round 是 system unit 里的函数，缺省就可以用。<br />floor 直接往小的取，比如 floor(-123.55)=-124，floor(123.55)=123<br />trunc 直接切下整数，比如 trunc(-123.55)=-123, floor(123.55)=123<br />ceil 直接往大的取，比如 ceil(-123.55)=-123， ceil(123.55)=124<br />round 计算四舍五入，比如 round(-123.55)=-124，round(123.55)=124</font>
<img src ="http://www.cppblog.com/erran/aggbug/34152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 21:34 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：C++的4种类型转换 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34150.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 13:27:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34150.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34150.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34150.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34150.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34150.html</trackback:ping><description><![CDATA[
		<font face="Arial">
				<font size="2">原文：http://blog.csdn.net/stanleyrprose/archive/2006/01/25/588083.aspx<br />作者：<br /></font>
				<br />
				<br />
				<b>C++的4种类型转换 </b>
				<br />
				<br />
				<br />
				<strong>一、C 风格（C-style）强制转型如下：</strong>
		</font>
		<p>
				<font face="Arial">    (T) expression // cast expression to be of type T <br />    函数风格（Function-style）强制转型使用这样的语法：<br />    T(expression) // cast expression to be of type T <br />    这两种形式之间没有本质上的不同，它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格（old-style）的强制转型。 </font>
		</p>
		<p>
				<font face="Arial">
						<strong>   二、 C++的四种强制转型形式：</strong>
				</font>
		</p>
		<p>
				<font face="Arial">　　C++ 同时提供了四种新的强制转型形式（通常称为新风格的或 C++ 风格的强制转型）： <br />　　const_cast(expression) <br />　　dynamic_cast(expression) <br />　　reinterpret_cast(expression) <br />　　static_cast(expression) </font>
		</p>
		<p>
				<font face="Arial">　　每一种适用于特定的目的： </font>
		</p>
		<p>
				<font face="Arial">　　·dynamic_cast 主要用于执行“安全的向下转型（safe downcasting）”，也就是说，要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型，也是唯一可能有重大运行时代价的强制转型。<br />    <br />   
·static_cast 可以被用于强制隐型转换（例如，non-const 对象转型为 const 对象，int 转型为
double，等等），它还可以用于很多这样的转换的反向转换（例如，void*
指针转型为有类型指针，基类指针转型为派生类指针），但是它不能将一个 const 对象转型为 non-const 对象（只有
const_cast 能做到），它最接近于C-style的转换。<br />    <br />　　·const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。 </font>
		</p>
		<p>
				<font face="Arial">　　·reinterpret_cast 是特意用于底层的强制转型，导致实现依赖（implementation-dependent）（就是说，不可移植）的结果，例如，将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。<br />　　<br />　
　旧风格的强制转型依然合法，但是新的形式更可取。首先，在代码中它们更容易识别（无论是人还是像 grep
这样的工具都是如此），这样就简化了在代码中寻找类型系统被破坏的地方的过程。第二，更精确地指定每一个强制转型的目的，使得编译器诊断使用错误成为可
能。例如，如果你试图使用一个 const_cast 以外的新风格强制转型来消除常量性，你的代码将无法编译。 </font>
		</p>
		<p>
				<font face="Arial">==  <br /><strong>==  dynamic_cast .vs. static_cast</strong><br />==</font>
		</p>
		<div class="Code">
				<p>
						<font face="Arial">class B { ... };<br />class D : public B { ... };</font>
				</p>
				<p>
						<font face="Arial">void f(B* pb)<br />{<br />   D* pd1 = dynamic_cast&lt;D*&gt;(pb);<br />   D* pd2 = static_cast&lt;D*&gt;(pb);<br />}</font>
				</p>
				<p>
						<font face="Arial">If
pb really points to an object of type D, then pd1 and pd2 will get the
same value. They will also get the same value if pb == 0. </font>
				</p>
				<p>
						<font face="Arial">If pb
points to an object of type B and not to the complete D class, then
dynamic_cast will know enough to return zero. However, static_cast
relies on the programmer’s assertion that pb points to an object of
type D and simply returns a pointer to that supposed D object.</font>
				</p>
		</div>
		<p>
				<font face="Arial">   
即dynamic_cast可用于继承体系中的向下转型，即将基类指针转换为派生类指针，比static_cast更严格更安全。
dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随
着不安全性.static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换,窄化变换(这种变换会导致对象切片,丢失信息),用
VOID*的强制变换,隐式类型变换等...</font>
		</p>
		<p>
				<font face="Arial">
						<br />==<br /><strong>==  static_cast .vs. reinterpret_cast</strong><br />==</font>
		</p>
		<p>
				<font face="Arial">    reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它.我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的.(这句话是C++编程思想中的原话)</font>
		</p>
		<p>
				<font face="Arial">   
static_cast 和 reinterpret_cast 操作符修改了操作数类型. 它们不是互逆的; static_cast
在编译时使用类型信息执行转换, 在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的. 另一方面,
reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换, 例子如下:</font>
		</p>
		<p>
				<font face="Arial">    int n=9; double d=static_cast &lt; double &gt; (n); </font>
		</p>
		<p>
				<font face="Arial">   
上面的例子中, 我们将一个变量从 int 转换到 double. 这些类型的二进制表达式是不同的. 要将整数 9 转换到 双精度整数 9,
static_cast 需要正确地为双精度整数 d 补足比特位. 其结果为 9.0. 而reinterpret_cast 的行为却不同: </font>
		</p>
		<p>
				<font face="Arial">    int n=9;<br />    double d=reinterpret_cast&lt;double &amp; &gt; (n); </font>
		</p>
		<p>
				<font face="Arial">    这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析. <br /></font>
		</p>
		<font face="Arial">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=588083</font>
<img src ="http://www.cppblog.com/erran/aggbug/34150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 21:27 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：如何在同一个工程里添加多种语言 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34149.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 13:24:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34149.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34149.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34149.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34149.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34149.html</trackback:ping><description><![CDATA[
		<span style="font-size: 11pt;" lang="EN-US">
		</span> 原文：http://dev.csdn.net/article/23/23538.shtm<br />作者： <span style="font-size: 11pt;" lang="EN-US"></span><span style="font-size: 11pt;" lang="EN-US"></span> <span style="font-size: 11pt;"><span lang="EN-US"><o:p></o:p></span></span> <span style="font-size: 11pt;" lang="EN-US"><o:p></o:p></span><span lang="EN-US"></span><span lang="EN-US"></span> <span lang="EN-US"></span> <span lang="EN-US"></span><span lang="EN-US"></span> <font face="Arial" size="2"><span id="ArticleContent1_ArticleContent1_lblContent"><p style="text-indent: 21pt;"><span style="font-size: 11pt;">这应该是一个使用<span lang="EN-US">VC的一个小技巧，不过在打算做之前，在网上找了找，没有找到（可能是我填入的关键字不对，:-)），所以在这里给大家提供一个参考，希望对大家能提供方便，不用象我找的这么辛苦。<o:p></o:p></span></span></p><p style="text-indent: 21pt;"><span style="font-size: 11pt;">意图：实现多种语言在同一个工程里，如果调试成功后，即可以同时编译程序的多种语言版本。<span lang="EN-US"><o:p></o:p></span></span></p><p style="text-indent: 21pt;"><span style="font-size: 11pt;">平台：<span lang="EN-US">Win2000 Pro SP4， VC＋＋6.0，SDK<o:p></o:p></span></span></p><p style="text-indent: 21pt;"><span style="font-size: 11pt;">一般情况下，编写程序都会使用工程制作向导，生成的工程有两个编译版本，一个是<span lang="EN-US">Debug，另外一个就是Release，我的目的就是添加多种语言的编译版本，同时需要多种语言的.rc文件（Source文件），然后经过一些简单的设置，就Okay了。<o:p></o:p></span></span></p><p><span style="font-size: 11pt;" lang="EN-US"><span style="">       </span>我添加很多的图片，这样比较容易理解，也少去读文字的痛苦（用电脑看大篇大篇的文字真的很痛苦）。<o:p></o:p></span></p><p><span style="font-size: 11pt;" lang="EN-US">  下面我们开始：<o:p></o:p></span></p><p><span style="font-size: 11pt;" lang="EN-US"> 
1.
首先是以工程文件里的.rc文件为基础，制作多种语言的.rc文件，就是把有关对话框，属性页，以及一些ID文字替换为其他的语言文字，这里需要注意的
是，不同语言版本的.rc文件，包含很多相同的图标（Icon），对话框（Dialog），String
Table，在VC编译器的SourceView里都要选择相应的语种。比如：如果是English，以上说的这些都要选择English（U.S.）。</span></p><p><span style="font-size: 11pt;" lang="EN-US">  2. 添加多语言编译版本，选择Build-&gt;Configurations，点击Add，添加相应的语言编译版本，我这里添加的是English Release。随后添加多种语言版本。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 11pt;">添加多种语言的编译版本</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 11pt;"><br />  3. 编辑不同语言版本的Project Setting。点击菜单Project-&gt;Settings，修改相应的设置<br />设置<span lang="EN-US">Output directories： 包括Intermediate和Output files，我这里都设置为English Release</span><br />设置<span lang="EN-US">Output file name： 我这里设置为English_Release/ktrexe.exe</span></span><span style="font-family: 宋体;"><span lang="EN-US"></span><br />设置</span><span lang="EN-US">Language</span><span style="font-family: 宋体;">：</span><span style="font-family: 宋体;">英语（美国）     </span><span style="font-family: 宋体;"></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><o:p></o:p></span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">4. </span><span style="font-family: 宋体;">添加</span><span lang="EN-US">Source Files</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"></span>  <span lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">添加后会弹出一个对话框，不用理会它</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">此时你可以在你编译器的</span><span lang="EN-US">ResourceView</span><span style="font-family: 宋体;">里看到：</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"></span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">以后如果需要修改不同的语言，可以修改相应的</span><span lang="EN-US">resources</span><span style="font-family: 宋体;">文件。</span></p><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US"><br style="page-break-before: always;" clear="all" /></span><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">5. </span><span style="font-family: 宋体;">点击</span><span lang="EN-US">Project-&gt;Settings</span><span style="font-family: 宋体;">，点击你所点击的</span><span lang="EN-US">.rc</span><span style="font-family: 宋体;">文件</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"></span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">选中</span><span lang="EN-US">Exclude file from build</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"></span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">选择“是”，每一种</span><span lang="EN-US">.rc</span><span style="font-family: 宋体;">文件分别选取相应的语言编译版本，比如</span><span lang="EN-US">Win32 English Release</span><span style="font-family: 宋体;">，选择</span><span lang="EN-US">Winapp1_English.rc</span><span style="font-family: 宋体;">，然后在</span><span lang="EN-US">Exclude file from build</span><span style="font-family: 宋体;">打勾即可。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">6. </span><span style="font-family: 宋体;">编译：</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">选择</span><span lang="EN-US">Build-&gt;Batch Build</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"></span> </p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">选中您所要编译的语种，选中</span><span lang="EN-US">Selection only</span><span style="font-family: 宋体;">，点击</span><span lang="EN-US">Rebuild All</span><span style="font-family: 宋体;">即可。</span><br /></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">7. </span><span style="font-family: 宋体;">此时，您可以看到您的</span><span lang="EN-US">.dsp</span><span lang="EN-US">文件已经被修改。<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">       </span></span><span style="font-family: 宋体;">我曾经在</span><span lang="EN-US">CSDN</span><span style="font-family: 宋体;">论坛上问过此问题，还有不同的解法，我把他们帖出来：</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">    </span></span><span style="font-family: 宋体;">我的操作是在</span><span lang="EN-US">VC++6.0</span><span style="font-family: 宋体;">里有一个用</span><span lang="EN-US">Win32</span><span style="font-family: 宋体;">程序向导生成的一个工程，此工程代码添加，调试，运行都已经</span><span lang="EN-US">Okay</span><span style="font-family: 宋体;">。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">    </span></span><span style="font-family: 宋体;">由于该工程是简体中文的，我想添加其他的语言版本，我就在</span><span lang="EN-US">.rc</span><span style="font-family: 宋体;">复本的基础上把简体中文的项目换成了其他的语言（比如西班牙语），然后我在</span><span lang="EN-US">Build-&gt;Configurations</span><span style="font-family: 宋体;">里添加了</span><span lang="EN-US">Spanish Release</span><span style="font-family: 宋体;">，在</span><span lang="EN-US">Project-</span><span style="font-family: 宋体;">〉</span><span lang="EN-US">Settings</span><span style="font-family: 宋体;">里设置了语言环境，输入路径等等属性。随后我就在</span><span lang="EN-US">Project-</span><span style="font-family: 宋体;">〉</span><span lang="EN-US">Add Files</span><span style="font-family: 宋体;">添加我刚才更换语言的</span><span lang="EN-US">.rc</span><span style="font-family: 宋体;">文件添加进来。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">    </span></span><span style="font-family: 宋体;">目的是用</span><span lang="EN-US">Debug</span><span style="font-family: 宋体;">调试，然后在</span><span lang="EN-US">Build-</span><span style="font-family: 宋体;">〉</span><span lang="EN-US">Batch Build</span><span style="font-family: 宋体;">选项里选择我要编译的语言种类，一次编译多种语言。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">    </span></span><span style="font-family: 宋体;">问题是</span><span lang="EN-US">VC6.0</span><span style="font-family: 宋体;">提示说“</span><span lang="EN-US">Multiple.rc
files exist in this project. Only one can be marked as included in the
build. The others will be excluded frome the build.</span><span style="font-family: 宋体;">”</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="">    </span></span><span style="font-family: 宋体;">请问，如何解决这个问题，我在网上找了两天了，在其他的</span><span lang="EN-US">Newsgroups</span><span style="font-family: 宋体;">上法帖，没有找到答案，是不是我哪里设置错了，请高手给个提示。谢谢！</span></p><div style="border-style: none none dotted; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 3pt; padding: 0cm 0cm 1pt;"><p class="MsoNormal" style="border: medium none ; margin: 0cm 0cm 0pt; padding: 0cm;"><span lang="EN-US"> <o:p></o:p></span></p></div><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">把你现在的</span><span lang="EN-US">.rc</span><span style="font-family: 宋体;">保存，然后把所有的中文换成其他语言，别存为其他</span><span lang="EN-US">other.rc</span><span style="font-family: 宋体;">。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">GetResourceInstance()</span><span style="font-family: 宋体;">得到资源句柄。换成另</span><span lang="EN-US">other.rc,(SetResourceHandle)</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">就可以搞定。</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">因为所有的</span><span lang="EN-US">id</span><span style="font-family: 宋体;">没变，</span><span style="font-family: 宋体;">所有程序都能正常运行。</span></p><div style="border-style: dotted none; border-color: windowtext -moz-use-text-color; border-width: 3pt medium; padding: 1pt 0cm;"><p class="MsoNormal" style="border: medium none ; margin: 0cm 0cm 0pt; padding: 0cm;"><span style="font-family: 宋体;">最好把资源做成</span><span lang="EN-US">dll,</span><span style="font-family: 宋体;">用</span><span lang="EN-US">LoadResource</span><span style="font-family: 宋体;">切换</span></p></div><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">写成</span><span lang="EN-US">INI</span><span style="font-family: 宋体;">也是一个好办法！</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">其他论坛的回答：</span></p><div style="border-style: none none dotted; border-color: -moz-use-text-color -moz-use-text-color windowtext; border-width: medium medium 3pt; padding: 0cm 0cm 1pt;"><p class="MsoNormal" style="border: medium none ; margin: 0cm 0cm 0pt; padding: 0cm;"><span lang="EN-US">Several solutions:<br />1. Place all your resources into one big. rc file.<br />2. Exclude the additional rc files from the build and include them by the<br />resource includes (right mouse click on the resource file in the resource<br />editor). In this case you have to take care that bitmaps and others are only<br />included once!<br />3. Create seperate DLL's for each language and use the corresponding handle<br />to this DLL when loading resources. Read the docu to AfxSetResourceHandle<br />when you are using the MFC.</span></p></div><p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;"><span lang="EN-US">1)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">      </span></span><span lang="EN-US">use the "resource includes" menu item in VC C++ 6.0 and include one<br />resource in the other (i.e. #include "file.rc")  Make sure that there are no<br />conflicts and each resource is properly marked with the correct language.<br />Mark the RC file as excluded from the build.  It will get built anyway since<br />it was included in the main RC.</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;"><span lang="EN-US">2)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">      </span></span><span lang="EN-US">have separate DLL (i.e. a separate sub-project) for each RC file (the<br />satellite DLL approach to localization)</span></p><div style="border-style: dotted none; border-color: windowtext -moz-use-text-color; border-width: 3pt medium; padding: 1pt 0cm;"><p class="MsoNormal" style="border: medium none ; margin: 0cm 0cm 0pt; padding: 0cm;"><span lang="EN-US">If you are unhappy with having separate builds for each language then<br />you'll have to combine the .rc files with (or without if they doesn't use<br />same identifiers) the proper LANGUAGE ID #ifdef's. If you don't know<br />about these, use the Resource editor built into the Environment to create<br />a new .rc with element variants in several languages. Then open the file<br />and analyse it.</span></p></div><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US">In VS.NET 2003 click on Build&gt;Configuration Manager<br />You will find your project. Now it is possible to select New in the combo<br />"Active Solution Configuration" you can add new settings to the current ones<br />Debug/Release.<br />In VS6 click on Build-&gt;Configurations. You will find your project displayed<br />as a tree. Click on Add to add new configurations.<br />In both caes you will be asked what base configuratin should be copied.<br /><br />Now you can create different Release modes like German/English/Bavarian and<br />so on...<br />For each configuration you can define diffrent rc files to be excluded from<br />the build. Also you can define different output directories.<br /><br />The disadvantage is that you always have a complete binary for a language<br />and you can not switch the language on user request!</span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"> <o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">如果有问题，请和我联系：</span><span lang="EN-US">danielxu22@cellink.com.cn</span></p></span></font><img src ="http://www.cppblog.com/erran/aggbug/34149.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 21:24 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34149.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：堆和栈的区别 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34148.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 13:12:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34148.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34148.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34148.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34148.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34148.html</trackback:ping><description><![CDATA[
		<br />
		<a href="http://kb.csdn.net/.net/Articles/200605/80f93200-6a0c-4e21-82d8-4212844da589.html" target="_blank">参见http://kb.csdn.net/.net/Articles/200605/80f93200-6a0c-4e21-82d8-4212844da589.html</a>
		<br />
		<br />
		<br />堆和栈的区别 
<br /><br /><br />一般认为在c中分为这几个存储区 
<br />1栈 - 有编译器自动分配释放 
<br />2堆 - 一般由程序员分配释放，若程序员不释放，程序结束时可能由OS回收 
<br />3全局区（静态区），全局变量和静态变量的存储是放在一块的，初始化的全局变量和静 
<br />态变量在一块区域，未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 
<br />- 程序结束释放 
<br />4另外还有一个专门放常量的地方。 - 程序结束释放 
<br />在函数体中定义的变量通常是在栈上，用malloc, calloc, realloc等分配内存的函数分 
<br />配得到的就是在堆上。在所有函数体外定义的是全局量，加了static修饰符后不管在哪 
<br />里都存放在全局区（静态区）,在所有函数体外定义的static变量表示在该文件中有效， 
<br />不能extern到别的文件用，在函数体内定义的static表示只在该函数体内有效。另外， 
<br />函数中的"adgfdf"这样的字符串存放在常量区。 
<br />比如： 
<br />int a = 0; 全局初始化区 
<br />char *p1; 全局未初始化区 
<br />main() 
<br />{ 
<br />int b; 栈 
<br />char s[] = "abc";栈 
<br />char *p2; 栈 
<br />char *p3 = "123456"; 123456\0在常量区，p3在栈上。 
<br />static int c =0； 全局（静态）初始化区 
<br />p1 = (char *)malloc(10); 
<br />p2 = (char *)malloc(20); 
<br />分配得来得10和20字节的区域就在堆区。 
<br />strcpy(p1, "123456"); 123456\0放在常量区，编译器可能会将它与p3所指向的"12345 
<br />6"优化成一块。 
<br />} 
<br />还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。 
<br />栈的空间大小有限定，vc的缺省是2M。栈不够用的情况一般是程序中分配了大量数组和 
<br />递归函数层次太深。有一点必须知道，当一个函数调用完返回后它会释放该函数中所有 
<br />的栈空间。栈是由编译器自动管理的，不用你操心。 
<br />堆是动态分配内存的，并且你可以分配使用很大的内存。但是用不好会产生内存泄漏。 
<br />并且频繁地malloc和free会产生内存碎片（有点类似磁盘碎片），因为c分配动态内存时 
<br />是寻找匹配的内存的。而用栈则不会产生碎片。 
<br />在栈上存取数据比通过指针在堆上存取数据快些。 
<br />一般大家说的堆栈和栈是一样的，就是栈(stack)，而说堆时才是堆heap. 
<br />栈是先入后出的，一般是由高地址向低地址生长。 
<br /><br /><br />堆(heap)和栈(stack)是C/C++编程不可避免会碰到的两个基本概念。<br />首先，这两个概念都可以在讲数据结构的书中找到，他们都是基本的数据结构，虽然栈更为简单一些。在具体的C/C++编程框架中，这两个概念并不是并行的。对底层机器代码的研究可以揭示，栈是机器系统提供的数据结构，而堆则是C/C++函数库提供的。 具体地说，现代计算机(串行执行机制)，都直接在代码底层支持栈的数据结构。这体现在，有专门的寄存器指向栈所在的地址，有专门的机器指令完成数据入栈出栈的操作。 

这种机制的特点是效率高，支持的数据有限，一般是整数，指针，浮点数等系统直接支 持的数据类型，并不直接支持其他的数据结构。因为栈的这种特点，对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈，然后跳转至子程序地址的操作，而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转之的操作。C/C++中的自动变量是直接利用栈的例子，这也就是为什么当函数返回时，该函数的自动变量自动失效的原因(因为 颜换指戳说饔们暗 状态)。 

和栈不同，堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的，而是由函数库提供的。基本的malloc/realloc/free函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时，这套函数首先试图从内部堆中寻找可用的内存空间，如果没有可以使用的内存空间，则试图利用系统调用来动态增加程序数据段的内存大小，新分配得到的空间首先被组织进内部堆中去，然后再以适当的形式返回给调用者。当程序释放分配的内存空间时，这片内存空间被返回内部堆结构中，可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间)，以更适合下一次内存分配申请。<br />这套复杂的分配机制实际上相当于一个内存分配的缓冲池(Cache)，使用这套机制有如下若干原因： 
<br />1. 系统调用可能不支持任意大小的内存分配。有些系统的系统调用只支持固定大小及其倍数的内存请求(按页分配)；这样的话对于大量的小内存分类来说会造成浪费。<br />2. 系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。
<br />3. 没有管理的内存分配在大量复杂内存的分配释放操作下很容易造成内存碎片。 

<br /><br />堆和栈的对比 

从以上知识可知，栈是系统提供的功能，特点是快速高效，缺点是有限制，数据不灵活；而栈是函数库提供的功能，特点是灵活方便，数据适应面广泛，但是效率有一定降低。栈是系统数据结构，对于进程/线程是唯一的；堆是函数库内部数据结构，不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的，比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的)，也就没有释放函数。为可移植的程序起见，栈的动态分配操作是不被鼓励的！堆空间的分配总是动态的，虽然程序结束时所有的数据空间都会被释放回系统，但是精确的申请内存/释放内存匹配是良好程序的基本要素。 

<br />所以计算机中的堆和栈经常时放一块讲的
<br />nod 一般不是必要就不要动态创建，最讨厌把new出来的东西当局部变量用，<br />用万了马上delete 的做法.<br /><br /> 理由<br /> 1.栈分配比堆快，只需要一条指令就呢给配所有的局部变量 
<br />2.栈不会出现内存碎片 
<br />3。栈对象好管理 

<br /><br />当然，某些情况下也要那么写,比如 
<br />1.对象很大 
<br />2.对象需要在某个特定的时刻构造或析够 
<br />3.类只允许对象动态创建,比如VCL的大多数类 

当然，必须用堆对象时也不能躲避<br /> <br /><a href="http://kb.csdn.net/.net/Articles/200605/80f93200-6a0c-4e21-82d8-4212844da589.html" target="_blank">http://kb.csdn.net/.net/Articles/200605/80f93200-6a0c-4e21-82d8-4212844da589.html</a><img src ="http://www.cppblog.com/erran/aggbug/34148.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 21:12 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34148.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：改变VC++应用程序窗口的标题</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34140.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 12:02:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34140.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34140.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34140.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34140.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34140.html</trackback:ping><description><![CDATA[
		<div class="Section1">
				<p class="MsoNormal" style="line-height: 13.9pt; text-align: center;" align="center">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 16pt;">改变<span lang="EN">VC++应用程序窗口的标题<o:p></o:p></span></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="line-height: 13.9pt; text-align: center;" align="center">
						<font face="Arial" size="2">上海卢湾区业余大学<span lang="EN"><span style="">      </span>邵祖铭</span></font>
				</p>
				<p class="MsoNormal" style="margin-top: 15.1pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">摘<span lang="EN"><span style="">  </span>要:讨论基于MFC类库的Windows应用程序设计中,应用程序各种标题的改变方法。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">关键词<span lang="EN">:MFC Windows编程标题Visual C++<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">0 引言<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">有一个演示<span lang="EN">VC++中的消息处理的单文档应用程序。该程序开始运行的情况如下:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">窗口中的初始文档标题竞显示为<span lang="EN">Untitled,实在不尽人意。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">有些时候<span lang="EN">,
确实需要改变自编Windows应用程序窗口的标题。比如,想编一个标题名为"Communication
soft的软件。虽然在Windows95或Windows NT下,Visual C++(以下简称VC)可以生成以"Communication
soft为名的工程,但该工程下的C++类的名称也要带上这么多的字符,给编程带来不便。可以采用的方法是生成以"CS为名的工程,再把程序的标题改成
"Communication Soft。再比如,在多文档应用程序中,希望每个子窗口的标题并不是"主窗口标题t、"主窗口标题2</span></span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;">……这种类型<span lang="EN">,而是象"COM1速率"、"LPT并行口"……,即子窗口标题与主窗口标题无关。这时都需要改变各种窗口标题。下面介绍一下改变窗口标题所用的方法,所用的开发平台是usual C++5.0。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">1 单又挡接口(SDI)典型窗口标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">首先<span lang="EN">,来看看Windows SD!类型窗口标题栏的结构形式。用VC的AppWizard创建一个名为"Exam9的单文档类型的工程。开始运行时,程序主窗口标题形式如下:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.9pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">Untitled-Exam9<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">其中<span lang="EN">"Untitied"为文档标题,"Exam9"为主窗口标题。当用"File-Open</span></span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;">打开<span lang="EN">"wd1.exm"文裆以后,文档标题变为"wd1.exm"。</span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span lang="EN">所以程序主窗口标题栏的一般形式为:<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">文裆标题<span lang="EN">----主窗口标题<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">1.1 又档标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">既然文档标题是由工程中相应的文档类所控制的<span lang="EN">,了解这一点,就可在相应的文档类中,利用SetTitle()函数来改变文档标题。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">例：改变<span lang="EN">CExam9Doc::onNewDocument()函数为:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">BOOL CExam9Doc::OnNewDocument()<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">{<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">if(!CDocument::OnNewDocument())<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 42pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return FALSE-<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">SetTitle("文档标题");<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return TRUE;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">}<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">运行程序<span lang="EN">,则每次选择选单中的"文件"的"新建"选项时,标题就变成"文档标题-Exam9</span></span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;" lang="EN">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt;">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">1.2 主窗口标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">主窗口的标题默认是工程的文件名<span lang="EN">,正如前面Appvvazied生成的Exam9工程执行后,标题栏的形式总为"文档标题-Exam9。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">改变主窗口的标题方法有两种<span lang="EN">:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">第一种方法<span lang="EN">:利用ResourceView打开工程的资源,修改String Table中的<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">IDR_MAINFRAME的值。将原来的"Exam9\n\nExam9\nEXMFile(*.exm)\n.exm\nExam9.Document\nExam9 Document"改为"标题改变示例<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">\n\nExam9\nEXM File(*.exm)\n.exm\nExam9.Document\nExam9 Document"。这样改变后,主窗口标题就变为"-标题改变示例"。第二种方法:具体改变方法如下:<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">改变<span lang="EN"> CMainFrame的成员函数PreCreateWindowO为:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp;cs)<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">{<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">m_strTitle="上海市卢湾区业余大学</span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;" lang="EN">;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return CFrameWnd::PreCreateWindow(cs);<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">}<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">这样改变后<span lang="EN">,主窗口标题的形式就为"-上海市卢湾区业余大学"。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 0.7pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">M_strTile是CFrameWnd的保护成员(要得到m_strTile更详细的信息,请打开\msdev\mfc\include\afxwin.h文件)。CMainFrame则是CFrameWnd类的派生类。<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">在这两种改变方法中<span lang="EN">,第二种方法优先级高。也就是说,改变了m_strTitle的值后,IDR_MAlNFRAME的值就不起作用。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 3.35pt;">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">2 对多文挡接口(MDI)类型窗口标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">在<span lang="EN">MDI类型窗口中,主窗口标题和文档标题的次序,和SDl类型窗口中次序是不同的。结合具体例子说明,用VC的AppWizard创建一个名为"MDITitle"的多文挡类型的工程。创建完工程后,编译运行该工程,主窗口标题形式如下:"主窗口标题-文档标题"。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">2.l 文挡标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">MDI类型窗口的文档标题也是由相应的文档类控制的。改变方法同SDI类型窗口类似,要改变标题,只要在相应的文档类中利用SetTitle()函数来改变文档标题。<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">2.2 主窗口标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">MDI类型主窗口标题的改变方法同SDI类型窗口类似。改变主窗口标题也有两种方法,通过改变IDR_MAINFRAME或m_strTitle的值就可实现改变主窗口标题的目的。同样,改变了m_strTitle值后,IDR_MAINFRAME的值就不起作用。<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<b>
										<span style="font-size: 10.5pt;" lang="EN">2.3 子窗口标题的改变<o:p></o:p></span>
								</b>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">在默认情况下<span lang="EN">,MFC自动将子窗口标题设为该子窗口所打开的文档标题。但实际上,子窗口标题与该子窗口标题所打开的文档标题可以不一样。可做如下改动:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">利用<span lang="EN">ResourceView打开资源,修改String Table中的IDR_MAINFRAME的值为"上海市卢湾区业余大学",使得主窗口标题变成"上海市卢湾区业余大学"。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">并将<span lang="EN">BOOL CMDlTitleDoc::OnNewDocument()函数改为:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">BOOL CMDlTitleDoc::OnNewDocument()<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">{<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">if(!CDocument::OnNewDocument())<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 42pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return FALSE;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">static int count=0;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.9pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">char message[10];<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.2pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">wsprintf(message,"%s%d","文档",count);<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.2pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">SetTitle(message);<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 1.2pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">count++;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return TRUE;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">}<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">通过以上修改<span lang="EN">,主窗口标题栏被设置为:文档标题为"上海市卢湾区业余大学-文挡0"、"上海市卢湾区业余大学-文档1</span></span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;">……<b><span lang="EN"><o:p></o:p></span></b></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 4.55pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">一下针对子窗口标题的修改作如下改动<span lang="EN">:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">将<span lang="EN">CChildFrame::PrecreateWindow()函数改为:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">BOOL CChiidFrame::PrecreateWindow(CREATESTRUCT&amp;cs)<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">cs.style &amp;=~(LONG)FWS_ADDTOTlTLE;<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">return CMDIChildWnd::PrecreateWindow(cs);<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">}<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.15pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">要改变窗口类型<span lang="EN">, 这步工作必须做。常量问FWS_ADDTOTITLE是在文件\msdev\mfc\include\afxwin.h中定义。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.6pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">在<span lang="EN"> CMDlTitleView类中增加OnlnitialUpdate()函数:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.6pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">void CMDlTitleView::OnlnitiaiUpdate()<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.6pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">{<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.6pt; text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">CView::OninitialUpdate();<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="text-indent: 21pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">Getparent()-〉SetWindowText(GetDocument()-)GetTitle()+</span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;" lang="EN">-上海卢湾区业余大学</span>
								<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN">”</span>
								<span style="font-size: 10.5pt;" lang="EN">);<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">}<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">这样<span lang="EN">,子窗口的标题栏的形式就为"文档名-上海卢湾区业余大学"。<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 14.6pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;">参考资料<span lang="EN">:<o:p></o:p></span></span>
						</font>
				</p>
				<p class="MsoNormal" style="margin-top: 2.4pt;">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">[1]Michaei Morrison:Sams Tech Yourself MFC in 24Hours<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">[2]David krugiinski:Programming Microsoft Visual C++,FiHh Edition<o:p></o:p></span>
						</font>
				</p>
				<p class="MsoNormal" style="">
						<font face="Arial" size="2">
								<span style="font-size: 10.5pt;" lang="EN">[3]Kate Gregory:Special Edition Using Visual C++5<o:p></o:p></span>
						</font>
				</p>
		</div>
<img src ="http://www.cppblog.com/erran/aggbug/34140.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 20:02 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34140.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CToolTipCtrl使用</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34139.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 11:59:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34139.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34139.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34139.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34139.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34139.html</trackback:ping><description><![CDATA[
		<p align="left">
				<font size="3">ToolTip是Win32中一个通用控件，MFC中为其生成了一个类CToolTipCtrl，总的说来其使用方法是较简单的，下面讲一下它的一般用法和高级用法。</font>
		</p>
		<strong>
				<font size="3">一般用法步骤：</font>
		</strong>
		<br />
		<ol>
				<li>
						<p align="left">
								<font size="3">添加CToolTipCtrl成员变量 m_tt。</font>
						</p>
				</li>
				<li>
						<p align="left">
								<font size="3">在父窗口中调用EnableToolTips(TRUE);</font>
								<br />
						</p>
				</li>
				<li>
						<font size="3">在窗口的OnCreate（或者其他适当的位置）中向ToolTip中添加需要显示Tip的子窗口，并同时指定相应的显示字串CToolTipCtrl::AddTool(pWnd,"string to display")。</font>
						<br />
				</li>
				<li>
						<p align="left">
								<font size="3">重载父窗口的 BOOL PreTranslateMessage(MSG* pMsg) ，在函数中调用 m_tt.RelayEvent(pMsg)。</font>
						</p>
				</li>
		</ol>
		<font size="3">下面假设在窗口CWndYour中使用CToolTipCtrl</font>
		<pre>
				<font size="3">在类定义中添加变量说明：<br /><br />class CWndYour:xxx<br />{<br />	CToolTipCtrl m_tt;<br />}<br /><br />在OnCreate中添加需要显示Tip的子窗口<br />CWndYour::OnCreate(....)<br />{<br />	EnableToolTips(TRUE);<br />	m_tt.Create(this);<br />	m_tt.Activate(TRUE);<br />	CWnd* pW=GetDlgItem(IDC_CHECK1);//得到窗口指针<br />	m_tooltip.AddTool(pW,"Check1");//添加<br />........<br /><br />}<br /><br />在BOOL PreTranslateMessage(MSG* pMsg)中添加代码<br />BOOL CWndYour::PreTranslateMessage(MSG* pMsg)<br />{<br />	{<br />		m_tt.RelayEvent(pMsg);<br />	}<br />	return CParentClass::PreTranslateMessage(pMsg);<br />}<br /></font>
		</pre>
		<p align="left">
				<font size="3">这样当鼠标移动到相应的子窗口上时会显示出相应的ToolTip。</font>
		</p>
		<strong>
				<font size="3">动态改变ToolTip的显示内容的方法及步骤：</font>
		</strong>
		<br />
		<ol>
				<br />
				<li>
						<font size="3">上面所讲的1、2、4步骤。</font>
						<br />
				</li>
				<li>
						<font size="3">在增加ToolTip时不指定显示的字串，而是使用LPSTR_TEXTCALLBACK。</font>
						<br />
				</li>
				<li>
						<font size="3">在窗口中增加消息映射 ON_NOTIFY_EX( TTN_NEEDTEXT, 0, SetTipText )。</font>
				</li>
				<li>
						<font size="3">
						</font>
						<p align="left">
								<font size="3">在窗口中增加一个函数用于动态提供显示内容，其原型为 BOOL SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult )，下面的代码可以根据传入的参数判定应该显示的内容。</font>
						</p>
				</li>
		</ol>
		<pre>
				<font size="3">BOOL CWndYour::SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult )<br />{<br />	TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pTTTStruct;    <br />	UINT nID =pTTTStruct-&gt;idFrom; //得到相应窗口ID，有可能是HWND<br />	if (pTTT-&gt;uFlags &amp; TTF_IDISHWND)    //表明nID是否为HWND<br />	{<br />	        nID = ::GetDlgCtrlID((HWND)nID);//从HWND得到ID值，当然你也可以通过HWND值来判断<br />		switch(nID)<br />		case(IDC_YOUR_CONTROL1)        <br />			strcpy(pTTT-&gt;lpszText,your_string1);//设置<br />			return TRUE;<br />		break;<br />		case(IDC_YOUR_CONTROL2)<br />			//设置相应的显示字串<br />			return TRUE;<br />		break;<br />	}<br />	return(FALSE);<br />}</font>
		</pre>
<img src ="http://www.cppblog.com/erran/aggbug/34139.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 19:59 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34139.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中取代状态栏默认“就绪”提示</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34138.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 11:55:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34138.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34138.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34138.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34138.html</trackback:ping><description><![CDATA[
		<div class="cnt">
				<p>
						<font face="Arial" size="2">在MFC程序中如果使用默认的状态栏的话，其第一栏在空闲时显示的是“就绪”，如果用户点击菜单，还会用于显示菜单栏的提示文本，如“建立新文档”等。有时候我们不希望程序在状态栏中显示这些东西，那该怎么办呢？</font>
				</p>
				<p>
						<font face="Arial" size="2">在MFC中，是用主框架类中的CStatusBar对象m_wndStatusBar来管理状态栏的。CStatusBar中有一个SetPaneText的函数可用于设置状态栏中的文字。我们在CMainFrame类中的OnCreate函数中添加</font>
				</p>
				<p>
						<font face="Arial" size="2">m_wndStatusBar.SetPaneText(0, "Hello");</font>
				</p>
				<p>
						<font face="Arial" size="2">则程序启动后，状态栏上显示的文字为“Hello”。但是当我们点击菜单后，会发现这段文字会消失，被替换成菜单的提示文本；若菜单操作结束，则又显示成“就绪”了。那该如何禁止MFC自动修改状态栏文本呢？</font>
				</p>
				<p>
						<font face="Arial" size="2">我们再看看主框架类的源程序。当中有这么一段</font>
				</p>
				<p>
						<font face="Arial" size="2">static UINT indicators[] =<br />
{<br />
ID_SEPARATOR,<br />
ID_INDICATOR_CAPS,<br />
ID_INDICATOR_NUM,<br />
ID_INDICATOR_SCRL,<br />
};</font>
				</p>
				<p>
						<font face="Arial" size="2">而在OnCreate中有这么一段</font>
				</p>
				<p>
						<font face="Arial" size="2">m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))</font>
				</p>
				<p>
						<font face="Arial" size="2">这一句的作用是设置状态栏各部分的ID，默认的ID由indicators数组指定。由于MFC中把状态栏的第一栏设置为ID_SEPARATOR
了，这是一个MFC默认的ID，所以它有一系列默认的操作，如显示“就绪”二字。我们想禁止MFC自动操作状态栏就必须修改indicators数组。</font>
				</p>
				<p>
						<font face="Arial" size="2">我们打开Resource View，修改String Table，找到那堆ID_INDICATOR开头的，在后面新加一个ID_INDICATOR_1。然后修改CMainFrame中indicators的声明</font>
				</p>
				<p>
						<font face="Arial" size="2">static UINT indicators[] =<br />
{<br />
ID_INDICATOR_1,<br />
ID_INDICATOR_CAPS,<br />
ID_INDICATOR_NUM,<br />
ID_INDICATOR_SCRL,<br />
};</font>
				</p>
				<p>
						<font face="Arial" size="2">然后编译运行程序。我们会发现，MFC不会再自动修改状态栏的文本了，可是前面添加的一句<br />
m_wndStatusBar.SetPaneText(0, "Hello");<br />
也不起作用了。这是为什么呢？</font>
				</p>
				<p>
						<font face="Arial" size="2">
								<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_status_bars.3a_.updating_the_text_of_a_status.2d.bar_pane.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_status_bars.3a_.updating_the_text_of_a_status.2d.bar_pane.asp</a>
								<br />
MSDN上有一篇介绍如果修改状态栏文本的文章。当中有一句</font>
				</p>
				<p>
						<font face="Arial" size="2">Note   The SetText approach is recommended. It is possible to
perform this task at a slightly lower level by calling the CStatusBar
member function SetPaneText. Even so, you still need an update handler.
Without such a handler for the pane, MFC automatically disables the
pane, erasing its content.</font>
				</p>
				<p>
						<font face="Arial" size="2">意思大概是如果我们不为状态栏添加UPDATE的处理函数，MFC会自动禁止状态栏的该栏(pane)。按照MSDN的说法，我们需要增加UPDATE的处理函数。在MainFrm.h中添加</font>
				</p>
				<p>
						<font face="Arial" size="2">afx_msg void OnUpdate1(CCmdUI *pCmdUI);</font>
				</p>
				<p>
						<font face="Arial" size="2">在MainFrm.cpp中添加</font>
				</p>
				<p>
						<font face="Arial" size="2">ON_UPDATE_COMMAND_UI(ID_INDICATOR_1, OnUpdate1)</font>
				</p>
				<p>
						<font face="Arial" size="2">void CMainFrame::OnUpdate1(CCmdUI *pCmdUI)<br />
{<br />
 pCmdUI-&gt;Enable();<br />
}</font>
				</p>
				<p>
						<font face="Arial" size="2">这样我们就可以往状态栏的第一栏写文字，而避开MFC对其的自动修改了。</font>
				</p>
		</div>
<img src ="http://www.cppblog.com/erran/aggbug/34138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 19:55 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Teach Yourself Programming in Ten Years </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34131.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 10:00:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34131.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34131.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34131.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34131.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"><strong>10年编程无师自通<br><br></strong>出处：Teach&nbsp;Yourself&nbsp;Programming&nbsp;in&nbsp;Ten&nbsp;Years&nbsp;,Peter&nbsp;Norvig&nbsp;郭晓刚翻译 </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">为什么每个人都急不可耐？&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">走进任何一家书店，你会看见《Teach&nbsp;Yourself&nbsp;Java&nbsp;in&nbsp;7&nbsp;Days》（7天Java无师自通）的旁边是一长排看不到尽头的类似书籍，它们要教会你Visual&nbsp;Basic、Windows、Internet等等，而只需要几天甚至几小时。我在Amazon.com上进行了如下搜索：&nbsp;<br>　　　　pubdate:&nbsp;after&nbsp;1992&nbsp;and&nbsp;title:&nbsp;days&nbsp;and&nbsp;(title:&nbsp;learn&nbsp;or&nbsp;title:&nbsp;teach&nbsp;yourself)&nbsp;<br>　　　　(出版日期：1992年后&nbsp;and&nbsp;书名：天&nbsp;and&nbsp;（书名：学会&nbsp;or&nbsp;书名：无师自通）)&nbsp;<br>我一共得到了248个搜索结果。前面的78个是<a class=channel_keylink href="http://www.easylib.org/"><u><font color=#0000ff>计算机</font></u></a>书籍（第79个是《Learn&nbsp;Bengali&nbsp;in&nbsp;30&nbsp;days》，30天学会孟加拉语）。我把关键词&#8220;days&#8221;换成&#8220;hours&#8221;，得到了非常相似的结果：这次有253本书，头77本是<a class=channel_keylink href="http://www.easylib.org/"><u><font color=#0000ff>计算机</font></u></a>书籍，第78&nbsp;本是《Teach&nbsp;Yourself&nbsp;Grammar&nbsp;and&nbsp;Style&nbsp;in&nbsp;24&nbsp;Hours》（24小时学会文法和文体）。头200本书中，有96%是<a class=channel_keylink href="http://www.easylib.org/"><u><font color=#0000ff>计算机</font></u></a>书籍。&nbsp;<br>结论是，要么是人们非常急于学会计算机，要么就是不知道为什么计算机惊人地简单，比任何东西都容易学会。没有一本书是要在几天里教会人们贝多芬或者量子物理学，甚至怎样帮狗打扮。&nbsp;<br>让我们来分析一下像《Learn&nbsp;Pascal&nbsp;in&nbsp;Three&nbsp;Days》（3天学会Pascal）这样的题目到底是什么意思：&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">学会：在3天时间里，你不够时间写一些有意义的<a class=channel_keylink href="http://www.easylib.org/programme/"><u><font color=#0000ff>程序</font></u></a>，并从它们的失败与成功中学习。你不够时间跟一些有经验的<a class=channel_keylink href="http://www.easylib.org/programme/"><u><font color=#0000ff>程序</font></u></a>员一起工作，你不会知道在那样的环境中是什么滋味。简而言之，没有足够的时间让你学到很多东西。所以这些书谈论的只是表面上的精通，而非深入的理解。如Alexander&nbsp;Pope（英国诗人、作家，1688-1744）所言，一知半解是危险的（a&nbsp;little&nbsp;learning&nbsp;is&nbsp;a&nbsp;dangerous&nbsp;thing）&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Pascal：在3天时间里你可以学会Pascal的语法（如果你已经会一门类似的语言），但你无法学到多少如何运用这些语法。简而言之，如果你是，比如说一个Basic<a class=channel_keylink href="http://www.easylib.org/programme/"><u><font color=#0000ff>程序</font></u></a>员，你可以学会用Pascal语法写出Basic风格的程序，但你学不到Pascal真正的优点（和缺点）。那关键在哪里？&nbsp;Alan&nbsp;Perlis（ACM第一任主席，图灵奖得主，1922-1990）曾经说过：&#8220;如果一门语言不能影响你对编程的想法，那它就不值得去学&#8221;。另一种观点是，有时候你不得不学一点Pascal（更可能是Visual&nbsp;Basic和javascript之类）的皮毛，因为你需要接触现有的工具，用来完成特定的任务。但此时你不是在学习如何编程，你是在学习如何完成任务。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">3天：不幸的是，这是不够的，正如下一节所言。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">10年编程无师自通&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">一些研究者（Hayes、Bloom）的研究表明，在许多领域，都需要大约10&nbsp;年时间才能培养出专业技能，包括国际象棋、作曲、绘画、钢琴、游泳、网球，以及神经心理学和拓扑学的研究。似乎并不存在真正的捷径：即使是莫扎特，他4&nbsp;岁就显露出音乐天才，在他写出世界级的音乐之前仍然用了超过13年时间。再看另一种音乐类型的披头士，他们似乎是在1964年的Ed&nbsp;Sullivan节目中突然冒头的。但其实他们从1957年就开始表演了，即使他们很早就显示出了巨大的吸引力，他们第一次真正的成功——Sgt.&nbsp;Peppers——也要到1967年才发行。Samuel&nbsp;Johnson（英国诗人）认为10&nbsp;年还是不够的：&#8220;任何领域的卓越成就都只能通过一生的努力来获得；稍低一点的代价也换不来。&#8221;（Excellence&nbsp;in&nbsp;any&nbsp;department&nbsp;can&nbsp;be&nbsp;attained&nbsp;only&nbsp;by&nbsp;the&nbsp;labor&nbsp;of&nbsp;a&nbsp;lifetime;&nbsp;it&nbsp;is&nbsp;not&nbsp;to&nbsp;be&nbsp;purchased&nbsp;at&nbsp;a&nbsp;lesser&nbsp;price.）乔叟（Chaucer，英国诗人，1340-1400）也抱怨说：&#8220;生命如此短暂，掌握技艺却要如此长久。&#8221;（the&nbsp;lyf&nbsp;so&nbsp;short,&nbsp;the&nbsp;craft&nbsp;so&nbsp;long&nbsp;to&nbsp;lerne.）&nbsp;<br>下面是我在编程这个行当里获得成功的处方：&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">对编程感兴趣，因为乐趣而去编程。确定始终都能保持足够的乐趣，以致你能够将10年时间投入其中。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">跟其他程序员交谈；阅读其他程序。这比任何书籍或训练课程都更重要。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">编程。最好的学习是从实践中学习。用更加技术性的语言来讲，&#8220;个体在特定领域最高水平的表现不是作为长期的经验的结果而自动获得的，但即使是非常富有经验的个体也可以通过刻意的努力而提高其表现水平。&#8221;（p.&nbsp;366），而且&#8220;最有效的学习要求为特定个体制定适当难度的任务，有意义的反馈，以及重复及改正错误的机会。&#8221;（p.&nbsp;20-21）《Cognition&nbsp;in&nbsp;Practice:&nbsp;Mind,&nbsp;Mathematics,&nbsp;and&nbsp;Culture&nbsp;in&nbsp;Everyday&nbsp;Life》（在实践中认知：心智、数学和日常生活的文化）是关于这个观点的一本有趣的参考书。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">如果你愿意，在大学里花上4年时间（或者再花几年读研究生）。这能让你获得一些工作的入门资格，还能让你对此领域有更深入的理解，但如果你不喜欢进学校，（作出一点牺牲）你在工作中也同样能获得类似的经验。在任何情况下，单从书本上学习都是不够的。&#8220;计算机科学的教育不会让任何人成为内行的程序员，正如研究画笔和颜料不会让任何人成为内行的画家&#8221;,&nbsp;Eric&nbsp;Raymond，《The&nbsp;New&nbsp;Hackers&nbsp;Dictionary》（新黑客字典）的作者如是说。我曾经雇用过的最优秀的程序员之一仅有高中学历；但他创造出了许多伟大的软件，甚至有讨论他本人的新闻组，而且股票期权让他达到我无法企及的富有程度（译注：指Jamie&nbsp;Zawinski，Xemacs和Netscape的作者）。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">跟别的程序员一起完成项目。在一些项目中成为最好的程序员；在其他一些项目中当最差的一个。当你是最好的程序员时，你要测试自己领导项目的能力，并通过你的洞见鼓舞其他人。当你是最差的时候，你学习高手们在做些什么，以及他们不喜欢做什么（因为他们让你帮他们做那些事）。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">接手别的程序员完成项目。用心理解别人编写的程序。看看在没有最初的程序员在场的时候理解和修改程序需要些什么。想一想怎样设计你的程序才能让别人接手维护你的程序时更容易一些。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">学会至少半打编程语言。包括一门支持类抽象（class&nbsp;abstraction）的语言（如Java或C++），一门支持函数抽象（functional&nbsp;abstraction）的语言（如Lisp或ML），一门支持句法抽象（syntactic&nbsp;abstraction）的语言（如Lisp），一门支持说明性规约（declarative&nbsp;specification）的语言（如Prolog或C++模版），一门支持协程（coroutine）的语言（如Icon或Scheme），以及一门支持并行处理（parallelism）的语言（如Sisal）。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">记住在&#8220;计算机科学&#8221;这个词组里包含&#8220;计算机&#8221;这个词。了解你的计算机执行一条指令要多长时间，从内存中取一个word要多长时间（包括缓存命中和未命中的情况），从磁盘上读取连续的数据要多长时间，定位到磁盘上的新位置又要多长时间。（答案在这里。）&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">尝试参与到一项语言标准化工作中。可以是ANSI&nbsp;C++委员会，也可以是决定自己团队的编码风格到底采用2个空格的缩进还是4个。不论是哪一种，你都可以学到在这门语言中到底人们喜欢些什么，他们有多喜欢，甚至有可能稍微了解为什么他们会有这样的感觉。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">拥有尽快从语言标准化工作中抽身的良好判断力。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"><br>抱着这些想法，我很怀疑从书上到底能学到多少东西。在我第一个孩子出生前，我读完了所有&#8220;怎样&#8230;&#8230;&#8221;的书，却仍然感到自己是个茫无头绪的新手。&nbsp;30个月后，我第二个孩子出生的时候，我重新拿起那些书来复习了吗？不。相反，我依靠我自己的经验，结果比专家写的几千页东西更有用更靠得住。&nbsp;<br>Fred&nbsp;Brooks在他的短文《No&nbsp;Silver&nbsp;Bullets》（没有银弹）中确立了如何发现杰出的软件设计者的三步规划：&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">尽早系统地识别出最好的设计者群体。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">指派一个事业上的导师负责有潜质的对象的发展，小心地帮他保持职业生涯的履历。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">让成长中的设计师们有机会互相影响，互相激励。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"><br>这实际上是假定了有些人本身就具有成为杰出设计师的必要潜质；要做的只是引导他们前进。Alan&nbsp;Perlis说得更简洁：&#8220;每个人都可以被教授如何雕塑；而对米开朗基罗来说，能教给他的倒是怎样能够不去雕塑。杰出的程序员也一样&#8221;。&nbsp;<br>所以尽管去买那些Java书；你很可能会从中找到些用处。但你的生活，或者你作为程序员的真正的专业技术，并不会因此在24小时、24天甚至24个月内发生真正的变化。&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">参考文献&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Bloom,&nbsp;Benjamin&nbsp;(ed.)&nbsp;Developing&nbsp;Talent&nbsp;in&nbsp;Young&nbsp;People,&nbsp;Ballantine,&nbsp;1985.&nbsp;<br>Brooks,&nbsp;Fred,&nbsp;No&nbsp;Silver&nbsp;Bullets,&nbsp;IEEE&nbsp;Computer,&nbsp;vol.&nbsp;20,&nbsp;no.&nbsp;4,&nbsp;1987,&nbsp;p.&nbsp;10-19.&nbsp;<br>Hayes,&nbsp;John&nbsp;R.,&nbsp;Complete&nbsp;Problem&nbsp;Solver,&nbsp;Lawrence&nbsp;Erlbaum,&nbsp;1989.&nbsp;<br>Lave,&nbsp;Jean,&nbsp;Cognition&nbsp;in&nbsp;Practice:&nbsp;Mind,&nbsp;Mathematics,&nbsp;and&nbsp;Culture&nbsp;in&nbsp;Everyday&nbsp;Life,&nbsp;Cambridge&nbsp;University&nbsp;Press,&nbsp;1988.&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">答案&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">各种操作的计时，2001年夏天在一台典型的1GHz&nbsp;PC上完成：&nbsp;<br>　　　　执行单条指令　　　　　　　　　　　　1&nbsp;纳秒&nbsp;=&nbsp;(1/1,000,000,000)&nbsp;秒&nbsp;<br>　　　　从L1缓存中取一个word　　　　　　　　2&nbsp;纳秒&nbsp;<br>　　　　从主内存中取一个word　　　　　　　　10&nbsp;纳秒&nbsp;<br>　　　　从连续的磁盘位置中取一个word　　　　200&nbsp;纳秒&nbsp;<br>　　　　从新的磁盘位置中取一个word（寻址）　8,000,000纳秒&nbsp;=&nbsp;8毫秒<br></p>
<img src ="http://www.cppblog.com/erran/aggbug/34131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 18:00 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：浅谈wince应用程序的可移植性</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34130.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34130.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34130.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34130.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34130.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34130.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;">原文：<a href="/milkyway/archive/2007/04/08/21481.html">http://www.cppblog.com/milkyway/archive/2007/04/08/21481.html</a><br />作者：<a id="viewpost1_TitleUrl" href="/milkyway/archive/2007/04/08/21481.html"><font color="#2e9ce9" size="3"><br /><br /><br />浅谈wince应用程序的可移植性</font></a></p>
		<p style="font-size: 10pt; font-family: Arial;">      由于windows绝大多数情况下运行于X86平台上，也就不存在不同平台的可移植性问题。然而Windows CE运行在四大架构（X86，SHx，MIPS，ARM）的CPU上，编写应用程序时就需要考虑它的移植。<br />       以下通过在wince系统下访问物理地址，来看看如何编写可移植性较好的应用程序。<br />       首先必须明确两个概念。<br />       1。在X86平台下才有I/O地址这一说，在其他体系的CPU（如ARM/MIPS）下是没有I/O端口的。因为X86下把I/O和存储器分开编址，导致其有两种地址；而别的CPU是把两者统一编址，即把I/O映射到存储器上。<br />        2。wince的存储管理是通过MMU实现的，在系统启动后，我们只能访问虚拟存储空间，必须经过MMU。但是在X86下，访问I/O口和存储器走的地址总线不同，不用经过MMU。<br />         比如我们想要访问挂在某总线上物理地址为360h的端口，对于X86平台我们可以直接嵌入汇编操作物理地址， 或者使用地址指针访问物理地址。但对于其他平台，我们必须先作一个物理地址到虚拟地址的映射，然后操作其虚拟地址。这样显然程序的可移植性不好，我们需要定义  #ifdef __x86....#elif defined __arm  使得在不同平台下程序能够顺利运行。<br />          如果使用下面的代码我们就可以不用这么费劲的定义不同平台了：<br />        先定义<br />     inIoSpace = 1;<br />    ioPhysicalBase.QuadPart = 0x360;</p>
		<p style="font-size: 10pt; font-family: Arial;">if( HalTranslateBusAddress( Isa,                 //此函数把ISA总线上物理地址映射为系统物理地址<br />                            0,<br />                            ioPhysicalBase,<br />                            &amp;inIoSpace,                  //此参数=1说明转化的是I/O空间地址，=0时存储器地址<br />                            &amp;ioPhysicalBase ) )<br />{<br />    if( !inIoSpace )                                           ////如果是存储器地址，针对非X86 平台<br /><br />    {<br />            ioPortBase = ( PUCHAR ) MmMapIoSpace(            //此函数把系统物理地址转化为虚拟地址<br />            ioPhysicalBase,<br />            IoLen,<br />            FALSE );<br />        if( ioPortBase == NULL )<br />        {<br />            //TODO: Error handling<br />        }<br />    }<br />    else                                                 //如果是I/O，即X86 下，不需要做地址映射<br />    {<br />        ioPortBase = ( PUCHAR ) ioPhysicalBase.LowPart;<br />    }<br />}<br />else<br />{<br />    //TODO: Error Handling<br />}</p>
		<p style="font-size: 10pt; font-family: Arial;">       随后对于端口的操作（ ioPortBase），我们也可以充分挖掘它的可移植性。通过使用READ_PORT_UCHAR, <br />WRITE_PORT_UCHAR这些wince下的宏来实现端口读写。而不是在X86下用指针操作（不仅移植性差，而且容易产生问题）。CE下的宏在内部是封装好的API函数。例如WRITE_PORT_UCHAR这个宏在X86 处理器上转化为一条OUT的汇编指令；而在ARM处理器上会转化成一条对虚拟地址的写指令。 </p>
<img src ="http://www.cppblog.com/erran/aggbug/34130.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:58 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34130.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：MultiByteToWideChar和WideCharToMultiByte用法详解</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34129.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:55:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34129.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34129.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34129.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34129.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34129.html</trackback:ping><description><![CDATA[
		<p>
				<span id="ContentBody" style="font-size: 10pt; font-family: Arial;">
				</span>
		</p>
		<p>在进行ce的开发时，经常设计到字符的转换，特别是系统中包含网络通讯时，更是如此。ce中均是Unicode编码，而网络通讯一般都使用BYTE进行数据传输。</p>
		<p>以下是在网上找到的一篇文章，介绍的很详细。</p>
		<p> 1.使用方法详解<br /><br />  在本文开始之处,先简要地说一下何为短字符和宽字符.<br />  所谓的短字符,就是用8bit来表示的字符,典型的应用是ASCII码.而宽字符,顾名思义,就是用16bit表示的字符,典型的有UNICODE.关于windows下的ASCII和UNICODE的更多信息,可以参考这两本经典著作:《windows 程序设计》,《windows 核心编程》.这两本书关于这两种字符都有比较详细的解说.<br />  <br />  宽字符转换为多个短字符是一个难点,不过我们只要掌握到其中的要领,便可如鱼得水.<br />  好吧,那就让我们开始吧.<br />  <br />  这个是我们需要转化的多字节字符串:  <br />  char sText[20] = {"多字节字符串!OK!"};<br />  <br />  我们需要知道转化后的宽字符需要多少个数组空间.虽然在这个里程里面,我们可以直接定义一个20*2宽字符的数组,并且事实上将运行得非常轻松愉快.但假如多字节字符串更多,达到上千个乃至上万个,我们将会发现其中浪费的内存将会越来越多.所以以多字节字符的个数的两倍作为宽字符数组下标的声明绝对不是一个好主意.<br />  所幸,我们能够确知所需要的数组空间.<br />  我们只需要将MultiByteToWideChar()的第四个形参设为-1,即可返回所需的短字符数组空间的个数:<br />  DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);<br />  <br />  接下来,我们只需要分配响应的数组空间:<br />  wchar_t *pwText;<br />  pwText = new wchar_t[dwNum];<br />  if(!pwText)<br />  {<br />   delete []pwText;<br />  }<br />  <br />  接着,我们就可以着手进行转换了.在这里以转换成ASCII码做为例子:<br />  MultiByteToWideChar (CP_ACP, 0, psText, -1, sText, dwSize);<br />  <br />  最后,使用完毕当然要记得释放占用的内存:<br />  delete []psText;<br />  <br /> <br />  同理,宽字符转为多字节字符的代码如下:  <br />  wchar_t wText[20] = {L"宽字符转换实例!OK!"};<br />  DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);<br />  char *psText;<br />  psText = new char[dwNum];<br />  if(!psText)<br />  {<br />   delete []psText;<br />  }<br />  WideCharToMultiByte (CP_OEMCP,NULL,lpcwszStr,-1,psText,dwNum,NULL,FALSE);<br />  delete []psText;<br />  <br />   如果之前我们已经分配好空间,并且由于字符串较短,可以不理会浪费的空间,仅仅只是想简单地将短字符和宽字符相互转换,那有没有什么简便的方法呢?<br />   WIN32 API里没有符合这种要求的函数,但我们可以自己进行封装:<br />     <br />  //-------------------------------------------------------------------------------------<br />  //Description:<br />  // This function maps a character string to a wide-character (Unicode) string<br />  //<br />  //Parameters:<br />  // lpcszStr: [in] Pointer to the character string to be converted <br />  // lpwszStr: [out] Pointer to a buffer that receives the translated string. <br />  // dwSize: [in] Size of the buffer<br />  //<br />  //Return Values:<br />  // TRUE: Succeed<br />  // FALSE: Failed<br />  // <br />  //Example:<br />  // MByteToWChar(szA,szW,sizeof(szW)/sizeof(szW[0]));<br />  //---------------------------------------------------------------------------------------<br />  BOOL MByteToWChar(LPCSTR lpcszStr, LPWSTR lpwszStr, DWORD dwSize)<br />  {<br />    // Get the required size of the buffer that receives the Unicode <br />    // string. <br />    DWORD dwMinSize;<br />    dwMinSize = MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, NULL, 0);<br />  <br />    if(dwSize &lt; dwMinSize)<br />    {<br />     return FALSE;<br />    }<br />  <br />    <br />    // Convert headers from ASCII to Unicode.<br />    MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, lpwszStr, dwMinSize);  <br />    return TRUE;<br />  }<br />  <br />  //-------------------------------------------------------------------------------------<br />  //Description:<br />  // This function maps a wide-character string to a new character string<br />  //<br />  //Parameters:<br />  // lpcwszStr: [in] Pointer to the character string to be converted <br />  // lpszStr: [out] Pointer to a buffer that receives the translated string. <br />  // dwSize: [in] Size of the buffer<br />  //<br />  //Return Values:<br />  // TRUE: Succeed<br />  // FALSE: Failed<br />  // <br />  //Example:<br />  // MByteToWChar(szW,szA,sizeof(szA)/sizeof(szA[0]));<br />  //---------------------------------------------------------------------------------------<br />  BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)<br />  {<br />   DWORD dwMinSize;<br />   dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);<br />   if(dwSize &lt; dwMinSize)<br />   {<br />    return FALSE;<br />   }<br />   WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);<br />   return TRUE;<br />  }<br />  <br />  <br />  使用方法也很简单,示例如下:<br />  wchar_t wText[10] = {L"函数示例"};<br />  char sText[20]= {0};<br />  WCharToMByte(wText,sText,sizeof(sText)/sizeof(sText[0]));<br />  MByteToWChar(sText,wText,sizeof(wText)/sizeof(wText[0]));<br />  <br />  这两个函数的缺点在于无法动态分配内存,在转换很长的字符串时可能会浪费较多内存空间;优点是,在不考虑浪费空间的情况下转换较短字符串非常方便.<br /><br />  <br />2.MultiByteToWideChar()函数乱码的问题<br /><br />  有的朋友可能已经发现,在标准的WinCE4.2或WinCE5.0 SDK模拟器下,这个函数都无法正常工作,其转换之后的字符全是乱码.及时更改MultiByteToWideChar()参数也依然如此.<br />  不过这个不是代码问题,其结症在于所定制的操作系统.如果我们定制的操作系统默认语言不是中文,也会出现这种情况.由于标准的SDK默认语言为英文,所以肯定会出现这个问题.而这个问题的解决,不能在简单地更改控制面板的"区域选项"的"默认语言",而是要在系统定制的时候,选择默认语言为"中文".<br />  系统定制时选择默认语言的位置于:<br />  Platform -&gt; Setting... -&gt; locale -&gt; default language ,选择"中文",然后编译即可.<br /></p>
<img src ="http://www.cppblog.com/erran/aggbug/34129.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:55 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34129.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中成员函数的重载、覆盖与隐藏</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34128.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:52:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34128.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34128.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34128.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34128.html</trackback:ping><description><![CDATA[稍微懂得点oop的人都知道重载，那是多态性的重要体现！可是在c++中你能分清成员函数的重载、覆盖吗？这个好像也不难，重载存在与同一个类中，而覆盖存在于派生类于基类中！可是如果再加上隐藏呢？说实话，以前我从来没有听说过这个概念！也不知道自己曾经捏造的程序，出了多少问题！看看林锐在《高质量c++编程指南》中的解释。
<h2><font size=2><span><span><br>&nbsp;&nbsp;&nbsp; </span></span><span>成员函数的重载、覆盖（<span>override</span>）与隐藏很容易混淆，<span>C++</span>程序员必须要搞清楚概念，否则错误将防不胜防。<span> </h2>
<p></span></span></font></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<p><font size=2><chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><strong><span>8.2.1</span></strong></chsdate><strong><span> </span></strong><strong><span>重载与覆盖<span>
<p></span></span></strong></font></p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>成员函数被重载的特征：<span>
<p></span></span></font></p>
<p><span><font size=2>（<span>1</span>）相同的范围（在同一个类中）；<span>
<p></span></font></span></p>
<p><span><font size=2>（<span>2</span>）函数名字相同；<span>
<p></span></font></span></p>
<p><span><font size=2>（<span>3</span>）参数不同；<span>
<p></span></font></span></p>
<p><font size=2><span>（<span>4</span>）<span>virtual</span>关键字可有可无。</span><span>
<p></span></font></p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><strong><span>覆盖是指派生类函数覆盖基类函数，特征是：<span>
<p></span></span></strong></font></p>
<p><strong><span><font size=2>（<span>1</span>）不同的范围（分别位于派生类与基类）；<span>
<p></span></font></span></strong></p>
<p><strong><span><font size=2>（<span>2</span>）函数名字相同；<span>
<p></span></font></span></strong></p>
<p><strong><span><font size=2>（<span>3</span>）参数相同；<span>
<p></span></font></span></strong></p>
<p><strong><span><font size=2>（<span>4</span>）基类函数必须有<span>virtual</span>关键字。<span>
<p></span></font></span></strong></p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="1" month="2" year="2008"><span>8-2-1</span></chsdate>中，函数<span>Base::f(int)</span>与<span>Base::f(float)</span>相互重载，而<span>Base::g(void)</span>被<span>Derived::g(void)</span>覆盖。<span>
<p></span></span></font></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=574>
            <p><span><font size=2>#include &lt;iostream.h&gt;
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>class Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;void f(int x){ cout &lt;&lt; "Base::f(int) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2>void f(float x){ cout &lt;&lt; "Base::f(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;virtual void g(void){ cout &lt;&lt; "Base::g(void)" &lt;&lt; endl;}
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            <p><span>
            <p><font size=2>&nbsp;</font></p>
            </span>
            <p>&#160;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=574>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>class Derived : public Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;<strong><span>virtual</span></strong> void g(void){ cout &lt;&lt; "Derived::g(void)" &lt;&lt; endl;}
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            <p><span>
            <p><font size=2>&nbsp;</font></p>
            </span>
            <p>&#160;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=574>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>void main(void)
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>{
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;Derived&nbsp;d;
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;Base *pb = &amp;d;
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;pb-&gt;f(42); <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Base::f(int) 42
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;pb-&gt;f(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>); <span>&nbsp;&nbsp;&nbsp; </span>// Base::f(float) 3.14
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>&nbsp;pb-&gt;g(); <span>&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>// Derived::g(void)
            <p></font></span></p>
            <p><span><font size=2>}
            <p></font></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=center><span><font size=2>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="1" month="2" year="2008"><span>8-2-1</span></chsdate>成员函数的重载和覆盖<span>
<p></span></font></span></p>
<p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>
<p></font></span></p>
<p><font size=2><chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><strong><span>8.2.2</span></strong></chsdate><strong><span> </span></strong><strong><span>令人迷惑的隐藏规则</span></strong></font></p>
<p><font size=2><strong></strong></font><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>本来仅仅区别重载与覆盖并不算困难，但是<span>C++</span>的隐藏规则使问题复杂性陡然增加。这里&#8220;隐藏&#8221;是指派生类的函数屏蔽了与其同名的基类函数，规则如下：<span>
<p></span></span></font></p>
<p><strong><span><font size=2>（<span>1</span>）如果派生类的函数与基类的函数同名，但是参数不同。此时，不论有无<span>virtual</span>关键字，基类的函数将被隐藏（注意别与重载混淆）。<span>
<p></span></font></span></strong></p>
<p><font size=2><strong><span>（<span>2</span>）如果派生类的函数与基类的函数同名，并且参数也相同，但是基类函数没有<span>virtual</span>关键字。此时，基类的函数被隐藏（注意别与覆盖混淆）。</span></strong><span>
<p></span></font></p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>示例程序<chsdate w:st="on" isrocdate="False" islunardate="False" day="2" month="2" year="2008"><span>8-2-2</span></chsdate>（<span>a</span>）中：<span>
<p></span></span></font></p>
<p><span><font size=2>（<span>1</span>）函数<span>Derived::f(float)</span>覆盖了<span>Base::f(float)</span>。<span>
<p></span></font></span></p>
<p><span><font size=2>（<span>2</span>）函数<span>Derived::g(int)</span>隐藏了<span>Base::g(float)</span>，而不是重载。<span>
<p></span></font></span></p>
<p><span><font size=2>（<span>3</span>）函数<span>Derived::h(float)</span>隐藏了<span>Base::h(float)</span>，而不是覆盖。<span>
<p></span></font></span></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=581>
            <p><span><font size=2>#include &lt;iostream.h&gt;
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>class Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>virtual<span> </span>void f(float x){ cout &lt;&lt; "Base::f(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2>void g(float x){ cout &lt;&lt; "Base::g(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void h(float x){ cout &lt;&lt; "Base::h(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=581>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>class Derived : public Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp; </span>virtual<span> </span>void f(float x){ cout &lt;&lt; "Derived::f(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2>void g(int x){ cout &lt;&lt; "Derived::g(int) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void h(float x){ cout &lt;&lt; "Derived::h(float) " &lt;&lt; x &lt;&lt; endl; }
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=center><span><font size=2>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="2" month="2" year="2008"><span>8-2-2</span></chsdate>（<span>a</span>）成员函数的重载、覆盖和隐藏<span>
<p></span></font></span></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>据作者考察，很多<span>C++</span>程序员没有意识到有&#8220;隐藏&#8221;这回事。由于认识不够深刻，&#8220;隐藏&#8221;的发生可谓神出鬼没，常常产生令人迷惑的结果。<span>
<p></span></span></font></p>
<p><span><font size=2>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="2" month="2" year="2008"><span>8-2-2</span></chsdate>（<span>b</span>）中，<span>pb</span>和<span>pd</span>指向同一地址，按理说运行结果应该是相同的，可事实并非这样。<span>
<p></span></font></span></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=560>
            <p><span><font size=2>void main(void)
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>Derived&nbsp;d;
            <p></font></span></p>
            <p><span><font size=2>Base *pb = &amp;d;
            <p></font></span></p>
            <p><span><font size=2>Derived *pd = &amp;d;
            <p></font></span></p>
            <p><span><font size=2>// Good : behavior depends solely on type of the object
            <p></font></span></p>
            <p><span><font size=2>pb-&gt;f(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Derived::f(float) 3.14
            <p></font></span></p>
            <p><span><font size=2>pd-&gt;f(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Derived::f(float) 3.14
            <p></font></span></p>
            <p><span>
            <p><font size=2>&nbsp;</font></p>
            </span>
            <p>&#160;</p>
            <p><span><font size=2>// Bad : behavior depends on type of the pointer
            <p></font></span></p>
            <p><span><font size=2>pb-&gt;g(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Base::g(float) 3.14
            <p></font></span></p>
            <p><span><font size=2>pd-&gt;g(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Derived::g(int) 3<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>(surprise!)
            <p></font></span></p>
            <p><span>
            <p><font size=2>&nbsp;</font></p>
            </span>
            <p>&#160;</p>
            <p><span><font size=2>// Bad : behavior depends on type of the pointer
            <p></font></span></p>
            <p><span><font size=2>pb-&gt;h(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Base::h(float) 3.14<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>(surprise!)
            <p></font></span></p>
            <p><span><font size=2>pd-&gt;h(<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="3.14" unitname="F">3.14f</chmetcnv>);<span> </span>// Derived::h(float) 3.14
            <p></font></span></p>
            <p><span><font size=2>}
            <p></font></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=center><font size=2><span>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="2" month="2" year="2008"><span>8-2-2</span></chsdate>（<span>b</span>） 重载、覆盖和隐藏的比较</span><span>
<p></span></font></p>
<p><font size=2><chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><strong><span>8.2.3</span></strong></chsdate><strong><span> </span></strong><strong><span>摆脱隐藏<span>
<p></span></span></strong></font></p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>隐藏规则引起了不少麻烦。示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="3" month="2" year="2008"><span>8-2-3</span></chsdate>程序中，语句<span>pd-&gt;f(10)</span>的本意是想调用函数<span>Base::f(int)</span>，但是<span>Base::f(int)</span>不幸被<span>Derived::f(char *)</span>隐藏了。由于数字<span>10</span>不能被隐式地转化为字符串，所以在编译时出错。<span>
<p></span></span></font></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=567>
            <p><span><font size=2>class Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2>void f(int x);
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=567>
            <p><span><font size=2>class Derived : public Base
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>public:
            <p></font></span></p>
            <p><span><font size=2>void f(char *str);
            <p></font></span></p>
            <p><span><font size=2>};
            <p></font></span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=567>
            <p><span><font size=2>void Test(void)
            <p></font></span></p>
            <p><span><font size=2>{
            <p></font></span></p>
            <p><span><font size=2>Derived *pd = new Derived;
            <p></font></span></p>
            <p><span><font size=2>pd-&gt;f(10);<span>&nbsp;&nbsp;&nbsp; </span>// error
            <p></font></span></p>
            <p><span><font size=2>}
            <p></font></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=center><font size=2><span>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="3" month="2" year="2008"><span>8-2-3</span></chsdate><span> </span>由于隐藏而导致错误</span><span>
<p></span></font></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<p><font size=2><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>从示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="3" month="2" year="2008"><span>8-2-3</span></chsdate>看来，隐藏规则似乎很愚蠢。但是隐藏规则至少有两个存在的理由：<span>
<p></span></span></font></p>
<p><font size=2><span><span>u<span Times New Roman??>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>写语句<span>pd-&gt;f(10)</span>的人可能真的想调用<span>Derived::f(char *)</span>函数，只是他误将参数写错了。有了隐藏规则，编译器就可以明确指出错误，这未必不是好事。否则，编译器会静悄悄地将错就错，程序员将很难发现这个错误，流下祸根。<span>
<p></span></span></font></p>
<p><font size=2><span><span>u<span Times New Roman??>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>假如类<span>Derived</span>有多个基类（多重继承），有时搞不清楚哪些基类定义了函数<span>f</span>。如果没有隐藏规则，那么<span>pd-&gt;f(10)</span>可能会调用一个出乎意料的基类函数<span>f</span>。尽管隐藏规则看起来不怎么有道理，但它的确能消灭这些意外。<span>
<p></span></span></font></p>
<p><span>
<p><font size=2>&nbsp;</font></p>
</span>
<p>&#160;</p>
<p><span><font size=2>示例<chsdate w:st="on" isrocdate="False" islunardate="False" day="3" month="2" year="2008"><span>8-2-3</span></chsdate>中，如果语句<span>pd-&gt;f(10)</span>一定要调用函数<span>Base::f(int)</span>，那么将类<span>Derived</span>修改为如下即可。<span>
<p></span></font></span></p>
<p><span><font size=2>class Derived : public Base
<p></font></span></p>
<p><span><font size=2>{
<p></font></span></p>
<p><span><font size=2>public:
<p></font></span></p>
<p><span><font size=2>void f(char *str);
<p></font></span></p>
<p><span><font size=2>void f(int x) { Base::f(x); }
<p></font></span></p>
<p><span><font size=2>};
<p></font></span></p>
<img src ="http://www.cppblog.com/erran/aggbug/34128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:52 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>定制Wnd（对话框）窗口类名</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34126.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34126.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34126.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34126.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34126.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34126.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">定制Wnd（对话框）窗口类名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>一 主窗口为CWnd的派生类</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BOOL CMainWnd::PreCreateWindow(CREATESTRUCT&amp; cs) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WNDCLASS wndcls;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;wndcls, sizeof(WNDCLASS) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.style&nbsp;&nbsp; = CS_DBLCLKS;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.lpfnWndProc&nbsp; = AfxWndProc;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.hInstance&nbsp; = AfxGetInstanceHandle();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.hIcon&nbsp;&nbsp; = theApp.LoadIcon( IDR_MAINFRAME );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.hCursor&nbsp;&nbsp; = theApp.LoadStandardCursor( IDC_ARROW );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.hbrBackground = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.lpszMenuName&nbsp; = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.lpszClassName = _T("MyMainWnd");<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxRegisterClass( &amp;wndcls );<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cs.lpszClass = wndcls.lpszClassName;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return CMDIFrameWnd::PreCreateWindow( cs );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">二 主窗口为CDialog的派生类</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一步 在BOOL CMyApp::InitInstance()中 声明Dialog对象之前添加</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WNDCLASS wndcls;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::GetClassInfo( AfxGetInstanceHandle(), "#32770", &amp;wndcls );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wndcls.lpszClassName = _T("MyDialog");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxRegisterClass( &amp;wndcls );</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二步&nbsp; 有两种方法</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a&nbsp; 直接修改&#215;&#215;.rc文件</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDD_MY_DIALOG DIALOGEX 0, 0, 319, 152<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STYLE DS_SETFONT | DS_MODALFRAME |&nbsp; &#8230;&#8230;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EXSTYLE WS_EX_APPWINDOW<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAPTION "Lottery2"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLASS "MyDialog"//添加此行即可<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FONT 9, "MS Shell Dlg", 0, 0, 0x1</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp; 修改属性<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在IDE中修改&#215;&#215;.rc属性 vc6 取消Enable MFC features</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .net&nbsp; Mfc mode = FALSE</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Dialog属性中的class name 项中 输入 MyDialog即可<br><br><br>参考：<u><font color=#800080>VC++中定制个性化的对话框窗口类</font></u>&nbsp;<a href="http://blog.csdn.net/chinawash/archive/2006/06/25/832338.aspx">http://blog.csdn.net/chinawash/archive/2006/06/25/832338.aspx</a><br></p>
<img src ="http://www.cppblog.com/erran/aggbug/34126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:43 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34126.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：DBA的选择：几种流行的数据库系统 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34124.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:34:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34124.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34124.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34124.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34124.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;">原文：<a href="http://www.cnblogs.com/jplee/archive/2006/10/29/543382.html">http://www.cnblogs.com/jplee/archive/2006/10/29/543382.html</a><br />作者：<a href="http://jplee.cnblogs.com/">不再年轻.NET</a><br /><br /><strong>DBA的选择：几种流行的数据库系统</strong><br /><br /><br />最"容易"的数据库系统-Microsoft SQL Server<br /><br />　　如果你打算做一个DBA，建议你选择那些现在比较流行的数据库系统。这意味着你将有更多的就业机会、交流和培训机会，而且，流行自有流行的理由，你可以因此省心很多。当然，就业竞争压力也比较大。一般的入门者选择Microsoft SQL Server，这是非常适合中小型企业的数据库系统，熟悉Access的读者很容易就能初步使用Microsoft SQL Server，成为一个DBBS。 J<br />Microsoft SQL Server 7.0的报价，5用户版1399美金，增加用户时，127美金每用户。<br /><br />最"难"的数据库-无冕之王Oracle<br /><br />　　如果你有机会接触到Oracle，那可是个好机会。Oracle是目前最看好的数据库厂商，由于其强大的功能和可配置、可管理能力，Oracle DBA的薪资一般比其他数据库管理员的薪资要高。而且，Oracle在大中型企业的关键应用也更加普遍了。Oracle可以运行在Windows NT、Sun Solaris、Linux等平台下。很多情况下要求你不仅仅熟悉NT，还要你熟悉Unix；而且Oracle不太友善的界面和成箱的Oracle产品资料可能也是一个障碍。<br />Oracle 8i标准版的报价，如果运行在Windows NT，附带JServer和interMedia，支持5个并发用户，报价是3925美金每CPU。增加并发用户时，785美金每用户。增加附加的命名用户时，392.5美金每用户。<br /><br />数据库系统的贵族-IBM UDB/DB2<br /><br />　　作为30年数据库研究的成果，IBM DB2确实称得上"数据库系统的贵族"。不管是小型商业系统，还是大的银行系统，用DB2都是可以高枕无忧的。最近推出的新版DB2 6.1， 管理和调节工具更加卓越和便于使用。DB2 可以运行在Intel架构上，也可以运行在IBM的S/390大型计算机上。如果你所在的行业对IBM的机器特别地称道，建议你学习IBM DB2。<br /><br />DB2有两种版本：工作组版和企业版。工作组版999美元每服务器，外加249美元每个并发用户。而企业版是12500美元每个CPU，不限并发用户数量。 </p>
		<p style="font-size: 10pt; font-family: Arial;">以Java为中心的数据库-Sybase Adaptive Server Enterprise(ASE) 12.0<br /><br />　　即将发布的Sybase ASE 12.0，直接面向Java 程序员。这种以Java为中心的数据库系统，为那些准备在Java 平台下构建企业应用的企业来说，将是最好的选择。但是ASE称不上一个数据库领域的领先者，尽管相对于它以前的版本已经改进很多，并支持多个CPU和更多的并发，还有很多的新的特性。但Sybase的风光似乎已经不再。<br /><br />值得期盼的Informix Centaur<br /><br />　　有时候"第一"只是意味着你的对手需要等待更长的时间去赶上你。这正是1997年创立的Informix所面临的。Informix公司是率先将多媒体特性加入到关系数据库系统的大型数据库厂商之一。但是如今，IBM、Oracle、Sybase都已经跨越了这个概念。所以，Informix不得不寻求新的支撑来使自己区别于其他数据库厂商。这就是Informix Centaur的目标。Informix Centaur结合了Informix Dynamic Server 7.3的对象-关系数据库和Informix Universal Data Option 9.1，意在获得更好的适应性和多媒体支持。详情如何，我们拭目以待！<br /><br />DBA的薪资<br /><br />有很多因素影响到你作为DBA的薪资：</p>
		<ol>
				<ol>
						<li>你的经验和能力所决定的DBA等级
        </li>
						<li>你所熟悉的数据库系统
        </li>
						<li>你的个性特点和潜力 </li>
				</ol>
		</ol>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />　　下面的表说明了国内DBA人员的基本薪资状况，并说明了DAB等级和你所熟悉的数据库系统怎样影响到DBA的薪资。当然，这只是我个人掌握的情况，只能在一定程度上代表行业的平均水平。<br /></p>
		<table bgcolor="#003366" border="0" cellpadding="0" cellspacing="1" width="100%">
				<tbody>
						<tr align="center">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">DBA等级数据库系统</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">初级DBA年薪(万元)</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">中级DBA年薪(万元)</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">高级DBA年薪(万元)</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">Oracle</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">4 </p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">8</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">11</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">Microsoft SQL Server</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">3</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">5</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">8</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">IBM DB2</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">4</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">8</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">10</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">Sybase</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">3.5</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">6</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">8</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">Informix</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">4</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">7</p>
								</td>
								<td style="font-size: 10pt; font-family: Arial;">
										<p style="font-size: 10pt; font-family: Arial;">10</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p style="font-size: 10pt; font-family: Arial;">注：每年按13个月计算。表内数字为平均年薪。 </p>
<img src ="http://www.cppblog.com/erran/aggbug/34124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:34 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：关于SQLServer的若干注意事项 </title><link>http://www.cppblog.com/erran/archive/2007/10/13/34122.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:27:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34122.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34122.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34122.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34122.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">原文：<a href="http://www.cnblogs.com/jplee/archive/2006/12/05/583174.html"><span style="color: rgb(51, 51, 51);">http://www.cnblogs.com/jplee/archive/2006/12/05/583174.html</span></a><br /><span style="color: rgb(51, 51, 51);">作者：<a href="http://jplee.cnblogs.com/"><font color="#000080">不再年轻.NET</font></a></span><br /><br /><a id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/jplee/archive/2006/12/05/583174.html"><span style="color: rgb(51, 51, 51);"><strong>关于SQLServer的若干注意事项</strong></span></a></p>
		<br />
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">如果你正在负责一个基于SQL Server的项目，或者你刚刚接触SQL Server，你都有可能要面临一些数据库性能的问题，这篇文章会为你提供一些有用的指导（其中大多数也可以用于其它的DBMS）。
</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">        在这里，我不打算介绍使用SQL Server的窍门，也不能提供一个包治百病的方案，我所做的是总结一些经验----关于如何形成一个好的设计。这些经验来自我过去几年中经受的教训，一直来，我看到许多同样的设计错误被一次又一次的重复。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">你了解你的工具吗？</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">        不要轻视这一点，这是我在这篇文章中讲述的最关键的一条。也许你也看到有很多的SQL Server程序员没有掌握全部的T-SQL命令和SQL Server提供的那些有用的工具。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">        “什么？我要浪费一个<font size="2">月</font>的时间来学习那些我永远也不会用到的SQL命令？？？”，你也许会这样说。对的，你不需要这样做。但是你应该用一个周末浏览所有的T-SQL命令。在这里，你的任务是了解，将来，当你设计一个查询时，你会记起来：“对了，这里有一个命令可以完全实现我需要的功能”，于是，到MSDN查看这个命令的确切语法。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要使用游标</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       让我再重复一遍：不要使用游标。如果你想破坏整个系统的性能的话，它们倒是你最有效的首选办法。大多数的初学者都使用游标，而没有意识到它们对性能造成的影响。它们占用内存，还用它们那些不可思议的方式锁定表，另外，它们简直就像蜗牛。而最糟糕的是，它们可以使你的DBA所能做的一切性能优化等于没做。不知你是否知道每执行一次FETCH就等于执行一次SELECT命令？这意味着如果你的游标有10000条记录，它将执行10000次SELECT！如果你使用一组SELECT、UPDATE或者DELETE来完成相应的工作，那将有效率的多。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       初学者一般认为使用游标是一种比较熟悉和舒适的编程方式，可很不幸，这会导致糟糕的性能。显然，SQL的总体目的是你要实现什么，而不是怎样实现。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       我曾经用T-SQL重写了一个基于游标的存储过程，那个表只有100,000条记录，原来的存储过程用了40分钟才执行完毕，而新的存储过程只用了10秒钟。在这里，我想你应该可以看到一个不称职的程序员究竟在干了什么！！！</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       我们可以写一个小程序来取得和处理数据并且更新数据库，这样做有时会更有效。记住：对于循环，T-SQL无能为力。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">        我再重新提醒一下：使用游标没有好处。除了DBA的工作外，我从来没有看到过使用游标可以有效的完成任何工作。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">规范化你的数据表</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       为什么不规范化数据库？大概有两个借口：出于性能的考虑和纯粹因为懒惰。至于第二点，你迟早得为此付出代价。而关于性能的问题，你不需要优化根本就不慢的东西。我经常看到一些程序员“反规范化”数据库，他们的理由是“原来的设计太慢了”，可结果却常常是他们让系统更慢了。DBMS被设计用来处理规范数据库的，因此，记住：按照规范化的要求设计数据库。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要使用SELECT *</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">        这点不太容易做到，我太了解了，因为我自己就经常这样干。可是，如果在SELECT中指定你所需要的列，那将会带来以下的好处：</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">1 减少内存耗费和网络的带宽</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">2 你可以得到更安全的设计</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">3 给查询优化器机会从索引读取所有需要的列</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">了解你将要对数据进行的操作</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       为你的数据库创建一个健壮的索引，那可是功德一件。可要做到这一点简直就是一门艺术。每当你为一个表添加一个索引，SELECT会更快了，可INSERT和DELETE却大大的变慢了，因为创建了维护索引需要许多额外的工作。显然，这里问题的关键是：你要对这张表进行什么样的操作。这个问题不太好把握，特别是涉及DELETE和UPDATE时，因为这些语句经常在WHERE部分包含SELECT命令。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要给“性别”列创建索引</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       首先，我们必须了解索引是如何加速对表的访问的。你可以将索引理解为基于一定的标准上对表进行划分的一种方式。如果你给类似于“性别”这样的列创建了一个索引，你仅仅是将表划分为两部分：男和女。你在处理一个有1,000,000条记录的表，这样的划分有什么意义？记住：维护索引是比较费时的。当你设计索引时，请遵循这样的规则：根据列可能包含不同内容的数目从多到少排列，比如：姓名+省份+性别。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">使用事务</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       请使用事务，特别是当查询比较耗时。如果系统出现问题，这样做会救你一命的。一般有些经验的程序员都有体会-----你经常会碰到一些不可预料的情况会导致存储过程崩溃。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">小心死锁</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       按照一定的次序来访问你的表。如果你先锁住表A，再锁住表B，那么在所有的存储过程中都要按照这个顺序来锁定它们。如果你（不经意的）某个存储过程中先锁定表B，再锁定表A，这可能就会导致一个死锁。如果锁定顺序没有被预先详细的设计好，死锁是不太容易被发现的。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要打开大的数据集</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       在CSDN技术论坛中 :），一个经常被提出的问题是：我怎样才能迅速的将100000条记录添加到ComboBox中？这是不对的，你不能也不需要这样做。很简单，你的用户要浏览100000条记录才能找到需要的记录，他一定会诅咒你的。在这里，你需要的是一个更好的UI，你需要为你的用户显示不超过100或200条记录。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要使用服务器端游标</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       与服务器端游标比起来，客户端游标可以减少服务器和网络的系统开销，并且还减少锁定时间。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">使用参数查询</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       有时，我在CSDN技术论坛看到类似这样的问题：“SELECT * FROM  a WHERE a.id='A'B，因为单引号查询发生异常，我该怎么办？”，而普遍的回答是：用两个单引号代替单引号。这是错误的。这样治标不治本，因为你还会在其他一些字符上遇到这样的问题，更何况这样会导致严重的bug，除此以外，这样做还会使SQL Server的缓冲系统无法发挥应有的作用。使用参数查询， 釜底抽薪，这些问题统统不存在了。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">在程序编码时使用大数据量的数据库</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       程序员在开发中使用的测试数据库一般数据量都不大，可经常的是最终用户的数据量都很大。我们通常的做法是不对的，原因很简单：现在硬盘不是很贵，可为什么性能问题却要等到已经无可挽回的时候才被注意呢？</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要使用INSERT导入大批的数据</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       请不要这样做，除非那是必须的。使用UTS或者BCP，这样你可以一举而兼得灵活性和速度。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">注意超时问题</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       查询数据库时，一般数据库的缺省都比较小，比如15秒或者30秒。而有些查询运行时间要比这长，特别是当数据库的数据量不断变大时。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">不要忽略同时修改同一记录的问题</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       有时候，两个用户会同时修改同一记录，这样，后一个修改者修改了前一个修改者的操作，某些更新就会丢失。处理这种情况不是很难：创建一个timestamp字段，在写入前检查它，如果允许，就合并修改，如果存在冲突，提示用户。</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<strong>
						<font size="4">在细节表中插入纪录时，不要在主表执行SELECT MAX(ID)</font>
				</strong>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">       这是一个普遍的错误，当两个用户在同一时间插入数据时，这会导致错误。你可以使用<font face="宋体">SCOPE_IDENTITY，<code>IDENT_CURRENT</code>和<code>@@IDENTITY。如果可能，不要使用<font face="宋体">@@IDENTITY，因为在有触发器的情况下，它会引起一些问题（详见这里的<a href="http://expert.csdn.net/Expert/topic/1147/1147612.xml?temp=.3728754"><font color="#000080">讨论</font></a>）。</font></code></font></p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<font face="宋体" size="4">
								<strong>避免将列设为NULLable</strong>
						</font>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<font face="宋体">    如果可能的话，你应该避免将列设为NULLable。系统会为NULLable列的每一行分配一个额外的字节，查询时会带来更多的系统开销。另外，将列设为NULLable使编码变得复杂，因为每一次访问这些列时都必须先进行检查。</font>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<font face="宋体">    我并不是说NULLS是麻烦的根源，尽管有些人这样认为。我认为如果你的业务规则中允许“空数据”，那么，将列设为NULLable有时会发挥很好的作用，但是，如果在类似下面的情况中使用NULLable，那简直就是自讨苦吃。</font>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>CustomerName1<br />CustomerAddress1<br />CustomerEmail1<br />CustomerName2<br />CustomerAddress2<br />CustomerEmail3<br />CustomerName1<br />CustomerAddress2<br />CustomerEmail3</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>   如果出现这种情况，你需要规范化你的表了。</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<strong>
								<font size="4">尽量不要使用TEXT数据类型</font>
						</strong>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>   除非你使用TEXT处理一个很大的数据，否则不要使用它。因为它不易于查询，速度慢，用的不好还会浪费大量的空间。一般的，VARCHAR可以<font face="新宋体">更好的</font>处理你的数据。</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<strong>
								<font size="4">尽量不要使用临时表</font>
						</strong>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>   尽量不要使用临时表，除非你必须这样做。一般使用子查询可以代替临时表。使用临时表会带来系统开销，如果你是用COM+进行编程，它还会给你带来很大的麻烦，因为COM+使用数据库连接池而临时表却自始至终都存在。SQL Server提供了一些替代方案，比如Table数据类型。</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<strong>
								<font size="4">学会分析查询</font>
						</strong>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>SQL Server查询分析器是你的好伙伴，通过它你可以了解查询和索引是如何影响性能的。</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>
						<strong>
								<font size="4">使用参照完整性</font>
						</strong>
				</code>
		</p>
		<p style="font-size: 10pt; color: rgb(51, 51, 51);">
				<code>定义主健、唯一性约束和外键，这样做可以节约大量的时间。</code>
		</p>
<img src ="http://www.cppblog.com/erran/aggbug/34122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:27 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：一个老程序员的心理话</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34121.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:18:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34121.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34121.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34121.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34121.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;">原文：不详<br />作者：</p>
		<p style="font-size: 10pt; font-family: Arial;"> </p>
		<p style="font-size: 10pt; font-family: Arial;">一个老程序员的十年总结 </p>
		<p style="font-size: 10pt; font-family: Arial;">今年是我大学毕业满10年的日子，也是我投身it技术的第10年。一直想能对过去的经历做些回顾与反思，以更好地走向未来，但总没有笔。刚好csdn举办"讲述程序员的故事"征文，这件事成了一个引子，我终于趁着暑期有时间，敲了一天键盘，便有了这篇人生自述。<br />10年对于一个人来说是比较长的一个阶段，10年之后，同期大学毕业的同学情况差异之大，让人叹息命运之变幻莫测。<br />我在此记录下了我的生活足迹，由于时间较长，有些事记得不太清了，但我是尽量真实的记录当时的情况，有兴趣看我这篇长文的人请把我看成是一个在你我中间一块生活，一起喜怒哀乐，一起努力的平凡人，相信我们之间会有很多跨越时空的情感交流。<br />好，就说到此吧。<br />序</p>
		<p style="font-size: 10pt; font-family: Arial;">从1994到2003，不知不觉之间，我已在计算机技术的世界里沉浸了十年。有位哲人说过：如果一个人能用十年的时间专心致志地研究一门学问，或学习一门手艺，或从事一个职业，他一定能成为这个领域的专家。我天资平庸，但哲人的话是有道理的。我用十年的时间先成为了一名合格的程序员，再成为了一个重点大学计算机专业的大学教师。十年磨一剑，蓦然回首，年华如水，青春如歌！<br />我父母都是城市中的平民，家境仅能解决温饱，我想我可能代表了中国社会的一大类青年，我的经历与体会可能会对许多条件并不好的年青程序员有所启示：只要努力，天资差与环境不好都是可以克服的。因为我不是牛人，所以我不能教你如何成为牛人，我只是尽量真实地写下我的经历与感触，写一个平凡人的努力过程。我为我是一个软件开发者而自豪，为我从事的教书育人的事业而自豪，并愿意为中国落后的软件业尽己菲薄之力，为此，我人生无悔！<br />我想分为三部分讲述我的人生经历：<br />上篇：学习人生：主要是我学习计算机技术的经历与感触，时间跨度大约是从1994~1996年；<br />中篇：艰难人生：主要是我流迹社会，失业一年半，三次考研的痛苦经历；时间跨度大约是从1997~1999年；<br />下篇：实践人生：主要是我的技术实践经历：在公司打工，开发软件，毕业求职与教书生涯，时间跨度是1999~2003。<br />一 计算机是什么东西？</p>
		<p style="font-size: 10pt; font-family: Arial;">我是七十年代初在中国出生的那一代人，等我们长大开始读书时，文革已经结束，相对于我们的兄长，从我们这一代开始，以后出生的孩子都能受到较为正规的教育，这是我们幸运的地方。<br />也就是我们上小学的时候，七十年代末，以美国为技术资源中心的计算机技术开始在全球范围内迅猛发展，这时正是世界性的"软件危机"极为严重的时候，计算机技术各方面都在酝酿着新的突破，而此时比尔盖茨也正在准备构建他的明日微软帝国。<br />七十年代末与八十年代初，在我们的生活中，看不到一点计算机技术的影子，刚刚改革开放的中国，99%以上的人连"计算机"这个词恐怕都没听说过，中国游离于信息技术大门之外。<br />在"振兴中华"成为时代主旋律的八十年代，整个中国真的是呈现出一种勃勃的生机，这是一个民族在经历百年耻辱，十年挫折之后的再起步，象一些老歌---《金梭与银梭》，《在希望的田野上》等，就是当时青年的一种积极向上的精神风貌的体现。这种环境下，对于正在成长中的我们这一批少年，在潜意识中有极为深刻的影响，我们认为爱国与振兴中华是天经地义的事，并且成为了努力学习的主要动力（呵呵，现在的一些"愤青"---愤怒青年一定会说我们当时被"洗脑"了，也许真的是吧，这种信念确实会给人以极大的动力，我看不出有什么不好，至少我不会有现在这一批青年所经历的非常迷茫的感觉）。<br />1986年我考上了桂林市重点高中---桂林中学，在那儿，我第一次见到了电脑。</p>
		<p style="font-size: 10pt; font-family: Arial;">1．中学的计算机兴趣班</p>
		<p style="font-size: 10pt; font-family: Arial;">1987年我在桂林中学读高二，桂中是重点高中，条件较好，当时学校课外安排了两个班：无线电班和计算机班，我上的是计算机班，当时用的微机是apple ii，用basic编程。记得当时中国也开发了一种同档次的计算机，叫做中华学习机，要在中小学中大力推广，但apple ii后来发展成了著名的mac系列，并拥有了自己的操作系统，而中国的中华学习机，还有后来的小霸王等电脑学习机，都无疾而终了。<br />学校安排上机，有同学不知从哪找来了一些有趣的basic程序，什么"比翼双飞"，"飞机空战"等等，都是一些非常简单的小游戏，当时他抄了厚厚一本，一上机就敲一些到计算机中运行，而我是一点也不会，只有站在一边看的份。<br />那时会计算机的人很少，老师讲的我又不明白，考试的时候也不知道怎么过的。呵呵，后来我读研打工时，在网上看到洛阳一个高中生用vb编的一个"电子书童"程序，水平之高，我当时真是没法比。<br />1989年六四动乱，广西高考名额一下减了7000多，竞争激烈，十几人里才能取一个，由于压力过大，我高考前夕失眠，第二天考语文，120分的试卷当时只考了68分，因而与重点高校无缘。本想复读，但父母怕我来年考不上，一定要让我读广西大学，我万分不情愿地顺从了父母的意愿，去了我不喜欢的学校，读了我不喜欢的专业。男怕入错行，我在大学毕业后重新开始学我喜欢的专业，足足用了五六年的时间才转过来，真正成为一名合格的劳动者，走了一条长长的弯路，所以，父母的决定对缺乏经验与决断力的孩子而言，真的是非常重要。<br />现在想起来，父母当时没错，我也没错，那都是在时代与社会环境下的自然选择。</p>
		<p style="font-size: 10pt; font-family: Arial;">2．失败的四年本科与工作初期</p>
		<p style="font-size: 10pt; font-family: Arial;">作为六四之后第一批进入大学的本科生，我们学习了两年的"六四风波的反思"，四年里我是个老老实实的好学生，但四年除了玩命过了六级，什么也没学会。<br />记得大学第一节课就是basic语言，呵呵，也根本没学会，但我看来注定了要与basic难解难分了，后面的实践篇中我会讲我用basic开发的事。<br />大学里我学的专业是电力系统自动化，学过微机原理与fortran，上机时还用的是古老的主机加终端方式的计算机（叫做l/f机），我上机时真是一塌糊涂，因为这门课我从没学进去，也从没学懂过。有同学很厉害的，会用电脑打印出许多漂亮的图片（当然现在看起来很粗糙，针式打印机打的），我那时就称这些人为牛人了。<br />呵呵，我如果没记错的话，做超级解霸的梁肇新也是广西大学的，但不是我们系，记得我当时就已听到有关几个计算机牛人的事，估计其中就有他吧，如果我记错了，梁肇新先生请指正。在本科期间，我对电脑是神秘多于兴趣。这也说明我成为不了牛人与大师，天资有限。<br />后来，我发现一个普遍的规律，如果能成为计算机方面的牛人与大师，请去翻翻他们的传记，绝大多数在本科期间就已展露出他们的才华。而我们现在的中国高校，这么多的本科生都在为考试、考研、考托、考g而奔忙，这种填鸭式的应试教育体制，扼杀了太多学生的创造性。结果是一个学生在大学里读得越认真，就受到的错误影响越大，我是用好几年的时间反思才得出这个结论的。所以，中国高校十几年数以几十万计的本科生中出不了可编写linux内核的杰出人才，一点也不奇怪。<br />1993年我毕业了，用我总结的一段话来说，是：<br />一张白纸进来，一脑浆糊出去。<br />毕业后我分到了一所号称是"中港合资"的生产蓄电池的公司，呵呵，刚刚工作的日子让我这个单纯的大学生被生活好好的教训了一下，许多无法以前想象的社会现象让我目瞪口呆，年轻气盛导致穿了小鞋，还只能忍气吞声。吃了生活的一个闷棍，我才明白，我除了有张文凭，什么都不是！<br />当时，我感到最郁闷的是我在公司里什么都不会做，一个电机烧坏了我楞不知如何下手修，公司老总办公室里的灯不亮了，学电的大学生我花了半小时楞不知原因在哪！我学的东西没一样能用的。开始我还以为是因为我在学校里没认真学，但后来问了很多同学，90%以上的都有同感，我现在终于认识到这不单是我个人的错，我自认为在学校中是很努力的，从未偷懒过，但如果90%以上的学生所学不能服务社会，这种教育体制一定存在问题。<br />四年里，我的电脑知识与技能=0！<br />现在看起来，我浪费了宝贵的四年光阴！但当时的环境与认识水平，也只能如此了，没有当初的浪费，怎有后来的珍惜？这是人生必经的一个阶段。<br />二 漫长的理论学习时期</p>
		<p style="font-size: 10pt; font-family: Arial;">1．从电脑培训班开始</p>
		<p style="font-size: 10pt; font-family: Arial;">我毕业后的第一个工作单位是一个非常差的企业，我在那儿见识了几乎所有中国差的企业的弊端：人浮于事，拉帮结派，暗箭伤人，损公肥私……。可以想见，在这样的企业工作，人是多么的颓废。我在无聊之中过了大半年的时间。1994年4月的一天我去桂林新华书店买书，看到桂林电子工业学院老师举办一个电脑培训班，教打字、排版、常用dos命令等电脑使用基础，反正也没事，不如上个班学点东西吧。不曾想就是这样一个培训班，却根本影响了我的人生之路。<br />我清楚地记得当我第一次上机时，连电脑开关在哪都找不到，老师拿着一张五寸软盘，插入软驱，打开电源，在一阵"吱吱"的声音之后，屏幕上开始有英文字符出现，然后，教师在键盘上敲入几个键，电脑沉默一会，突然在屏幕上跳出一个小人，出现一行字：快快乐乐学电脑，还传出了音乐。我当时真是惊呆了，电脑怎么还会唱歌？现在想起来，那个软件其实是台湾松岗系列教学软件，而我一个大学本科生，在毕业之后居然对电脑无知到这个地步，我真不知道是该哭还是该笑……！<br />俗语说："一见钟情"。我是相信这种事的，因为就是这第一次上机，让我产生了搜索这一神秘世界的强烈兴趣，从此就再难与电脑分开了。<br />当时，有两位电子学院的老师：尹老师和陈老师。他们给我们讲dos，讲汉字输入，讲他们如何修改天汇汉字系统使它能在一张软盘上运行，讲打字排版……，一个月之后，我不满足，又学了一个月。<br />在上培训班的时间里，我向老师要来了桂林电子工业学院计算机应用专业本科四年的培养方案，回到家中，列出了所有本科课程，再根据书上的先修课程介绍，绘制了一张巨大的课程树，从树根开始，决定一本本地啃，从头开始学计算机技术。计算机科学的学习有较强的系列性，想一步到位很可能会学不懂，但循序渐进又无法跟上技术发展的速度，这是一个非常突出的问题。我现在想起来，觉得好的学习方式是：学理论打基础，在实践中逐步理解理论，多思多悟，就会发现层出不穷的新技术中有许多一直不变的东西存在。把握这种东西，就可以以不变应万变。这种"不变"的东西是什么？就是软件开发的基本原理与理论，基本思想与方法！在我对面向对象理论进行了较深入的学习与把握之后，我学.net只用了三个月的时间就可以独立设计一个完整的全面向对象软件架构，并且用vb.net与c#混合语言把它给做出来了。对于j2ee，我同样有这种自信，也用三个月的时间，一定可以开发与设计基于j2ee平台的软件，因为它们背后的计算机技术基础是一致的，完全可以触类旁通。<br />尹老师和陈老师可能不知道，他们开的一个也许是为了经济效益的培训班，最后居然培育出了一个计算机硕士！所以，作为一名教师，其责任真的是非常重大的，可能会影响学生的一辈子，我感激他们！</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />2．漫长而艰辛的学习之路<br />我当时每月只有一百多元的工资收入，把大半收入都用到买书上去了。电子工业学院门旁的那个科技书店，以及桂林科技书店，成为了我最常去"站读"的地方。我买了数据结构、操作系统、微机原理、ibmpc汇编程序设计，c程序设计……这些教材，就按照预定的计划开始学了。<br />我当时也说不清楚为什么要学这些东西，决不象现在学生学什么东西都有很强的功利性：学英语为了出国，学电脑为了好找工作。当时根本就没有想过今后如何如何，就是对计算机技术本身的兴趣推动我去学习的。<br />当时计算机书还不象现在这样扑天盖地，我几乎看完了我能弄到的每一本计算机书，看了一些书，就特别想有地方上机，能练一练。但我一个月一百多元收入，一台电脑怎么也得几千元，要五六年不吃不喝才攒够钱，父母都是普通百姓，家境仅能温饱，拥有一台电脑真成了我最大的美梦。<br />为了有机会上机，我这个脸皮极薄的人也会什么都顾不上了，带着一盒保存着各种软件的软盘，厚着脸皮到处找可能的地方上机。在这个时候，电子工业学院又一次帮了我，他们的机房管理得并不严，我就冒充是他们的学生去买机票上机。后来去得多了，那儿的老师都熟悉我这张脸了，但搞笑的是，居然没一人知道我是哪个班的！<br />当时电子学院用的局域网操作系统是novell，我在那儿学会了使用许多最基础的软件，现在仍然如数家珍：cpav，turbo pascal 5.5，ucdos，tway（天慧汉字系统），masm，turboc2.0，还有鼎鼎大名的norton公司的磁盘医生ndd，pctools，borland公司的最牛的常驻内存的软件sidekick，……<br />在电子学院机房，我还玩了经典游戏：决战中国海，冒险岛，战斧，三国……。<br />学校网络里软件很多，但其中所染的病毒也五花八门。我记忆深刻的是第一次遇见dir ii病毒时，那种感觉决不是害怕，而是欣喜，呵呵，我见到病毒什么样的啦！由于dos内核是开放的，所以那时开发一个病毒程序相对容易，大家又都喜欢用软盘拷来拷去，结果毒源泛滥，病毒的猖獗使得杀毒软件有了巨大的市场，现在大名鼎鼎的江民kv系列，就是在那时开始占据中国防毒市场，同时还有部的kill等竞争对手，瑞星，金山等都是后来者。<br />那时，我白天在公司上班，就盼望着晚上的上机，每次上机我都有详细的计划，因为机时宝贵，所以份外珍惜。<br />为了上机时能多敲些程序，我一咬牙，向妈妈要了两百元，买了一台电脑学习机，回家苦练英文指法与五笔输入，每天对着家里那台14寸的电视机屏幕，敲击至少键盘2小时以上。练得手腕酸疼，但终于达到了运指如飞盲打的程度。学五笔，背字根"目具上止卜虎皮，……"，足足花了一星期才背下来，并把每个字根与手指对应起来，后来看报纸都不自觉地将汉字给拆得七零八落，再也看不到是一个完整的汉字啦，当时好象练到了每分钟可打60多个字，后来我居然K着这弹指神功当了一阵打字员混饭吃！呵呵，练好了指法，一上机，确实效率倍增，两小时能敲入并运行调试的程序比以前花三小时敲的还多。<br />94，95年是我条件最差，但学习劲头最足的两年时期，外在环境的恶劣，却反而造就了我高昂的学习兴趣，那种痴迷，我想热恋也不过如此了，可能因为我太喜欢计算机了，所以爱情与我无缘，这也是无可奈何的事。 ：-（ <br />我特别想说说我学习计算机技术书籍的感觉。如果你真的喜欢一门学科，那在啃一本本专业书籍时，就决不会觉得它厚，而只嫌它不够厚。对比我在本科学《电磁学》、《自控原理》之类枯燥无味的课程的感觉，那种课程脱离实际，从纸上到纸上，学生根本无法真正掌握。而学计算机课程《c程序设计》、《数据结构》、《操作系统》等课程的感觉真是天壤之别，原来本科学的东西是越学越糊涂，而我在学习计算机科学的过程中自己就感到慢慢地将所有的知识串成了一条线，脑中有一棵知识树在成长，这不是形容词，是真的感受。我学dos命令，学了很久不明其道理，是在一天早上醒来时灵感一来，突然理解了文件与树的概念，于是，就真正把握了dos命令的内涵，开始对copy，format，move……这些英文单词游刃有余了。有段时间，我甚至能感觉得到我的知识在与日俱增！如果那时能有相对稳定的客观条件：比如有一台随时可用的计算机，那我一定学得更快更好。不过话又说回来，条件好的时候，人又容易为安逸所累，进步反而慢。还是那句老话：业精于勤荒于嬉。现在的许多学生就是物质条件太好了，反而不懂得珍惜。<br />后来我看了金庸先生的《射雕英雄传》，郭靖成了我最喜欢的人物，不是因为他有黄蓉的爱，而是他那种坚忍不拔的毅力，以平凡之资终登绝顶！金庸先生真是妙笔！此小说我不知看了多少遍。<br />最值得怀念的就是我学编程的岁月，我学c语言用的是谭浩强的《c程序设计》，当时谭老师在电视上同时讲c程序设计，我每天必看，把书上的每道例题与习题全部做了一遍，并写出了每次上机的安排。我每次都先在纸上把程序写出来，然后上机时争分夺秒地在计算机中调试运行，并根据运行结果思索为什么会运行不正常，在哪儿出错了，如何更正，上机完后还有总结。就是这样，我把谭浩强的《c程序设计》一书中的所有例题和习题全部敲到计算机中运行了一遍，打下了c语言扎实的基础。谭老师的书和课，的确影响了中国多少名程序员！<br />我学了c语言之后，就开始想做点东西了。我用了一个月的时间，用c编写了一个中文下拉菜单的程序，从ucdos中的字库中提取汉字点阵，然后在图形模式下"画"出汉字来，使程序能脱离汉字系统的支持直接显示汉字。整个程序应该有一两千行代码吧，全部是自己寻找资料，一行行敲进去的。后来，我又编了读取wps文件的程序（当时dos下打字排版是求伯君的wps一统天下，word当时在哪里我不知道呢！《电脑报》介绍过的求伯君，鲍岳桥等作为第一代中国杰出程序员代表，是我当时崇拜的偶像），我还编写了一个绘制简单图形的小程序，从编程调试的过程中，我得到了程序员基本功的最初训练。我当初没人教，遇见各种困难只能自己解决，为找出一个bug，晚上睡觉做梦都在编程，而现在的一些大学生，程序通不过，马上问老师，甚至有学生把程序发到我的邮箱，叫我帮他调程序！有的计算机专业学生，学了四年，四年敲过的代码总数恐怕不超过2千行！<br />的确，我当时的水平很低，现在的本科生比我当时强太多了，但至少有一点他们中的许多人不如我，他们不如我勤奋，也不具备我的毅力，我觉得这是现在这批八十年代出生的大学生最缺的东西。<br />我用一年半的时间基本自学完了计算机专业的主干课程（除了《编译原理》，我实在看不懂），1995年我参加了初级程序员考试，结果上下午成绩加起来有90多分。但96，97我两次参加程序员级考试，虽然我已有不少编程实践，但仍然通不过，现在看起来，这反映出一个事实：我理论基础实在太差，天资也并不高。直到现在，我仍然痛感我的计算机基础理论不好，使我难以成为一名计算机科学家，而只能成为一名不错的软件工程师。<br />从95年开始，我的生活开始加速下降，我所在的公司由于被一群我现在称之为驻虫与流氓的人给弄得不成样子，每月连100多元的工资都无法保证，我只得离开了公司，把档案往人才交流中心一放，就开始了我四年的社会漂浮生活……。<br />在这四年中，我干了不下四五种工作：当过推销员，当过打字员，当过培训老师，修过电脑，从事售后服务，甚至摆过地摊……，一切的一切，很简单，就为了能有口饭吃。生活是严厉的，不讲情面的，我唯一的爱好就是闲下来就拿起我的计算机书来看。当时我大哥说过：你学这些东西有什么用？能K它当饭吃？不要惊奇这种观点，在我们那信息闭塞的地方，当时有谁能想到计算机技术会有如此大的改变社会的能力？我之所以不懈学习，纯粹是为了解脱精神上的困惑，在技术的海洋中忘却生活的烦恼。我后来有一句名言：何以解忧，唯有电脑。别人当作一句笑话，但却是我当时的真实写照。<br />万事都有两面，事情坏到极处，就会向好转化。又是一个很偶然的事，改变了我的人生轨迹。<br />1996年，我的一个高中同学杨考上了湖南大学计算机系研究生，请客吃酸菜鱼火锅。在大家喝酒时，杨提了一个问题：请大家说出一个自己最想达到的目标。我的桂中同学大多数都是上的全国重点大学，此时毕业三年了，大家都对社会对生活有了自己的认识，于是就有了各种不同的答案，我当时的回答是："我希望能有一天开发出一个好的软件，让许许多多的人都能用上它。"，这个目标我到现在都没达到。但当时大家是给我热烈地鼓励。杨饭后跟我说，你既然那么喜欢计算机，为什么不考研呢？对啊，我为什么不去试试呢？当天晚上我躺在床上，没怎么想就确定了要考研的想法。当时却怎么也没想到，考研之路成了另一条折磨人的不归路。对我一生的影响深远……<br />这就是我早期的学习生涯，深深地体现出中国的时代特色。这段时间我的生活是困苦的，心情是苦闷的，但学习热情却是无以伦比的。现在我一个人拥有两台奔四电脑，随时可上互联网获取丰富的资源，反而在技术上难有寸进了。越来越觉得古语说得好：<br />艰难困苦，玉汝于成！<br />这是生活的真理！<br />第一次考研的失败</p>
		<p style="font-size: 10pt; font-family: Arial;">艰难人生<br />-------一个普通it人的十年回顾（中）</p>
		<p style="font-size: 10pt; font-family: Arial;">在上篇中我说到决定考研，从此迈上了一条对我来说到目前为止最难走的路，是一个人生的炼狱。</p>
		<p style="font-size: 10pt; font-family: Arial;">第一次考研的失败</p>
		<p style="font-size: 10pt; font-family: Arial;">决定考研之后，我就去买了相关资料，取出尘封己久差点当废纸卖掉的大学课本，又开始了学生生涯。<br />考哪儿的大学？是我首先要考虑的问题。<br />当时还有另一个高中同学也准备考研，也是计算机，他报了广西师范大学的研究生。<br />父母则劝我也考广西师大或我的母校广西大学的研究生，说那好考得多，也可以托人走走关系。但我这人很犟，我在西大混了4年，什么也没学到，我还去那儿干什么？我想起了高中时的梦想，决定直接考北京的高校。当然，北大清华是想都不敢想的，社会上工作几年，我毕竟清楚自己几斤几两，但北京几十所高校，难道一所也不行？我不能再听父母的话了，我要走自己的路，自己的命运自己负责，于是我坚持要考北京的学校。<br />知道这件事的朋友都对我表示惊奇，工作了4年，学校里的知识都忘得差不多了，还想直接考北京的学校，难度之大，相信不少人都认为我成功的希望很渺茫。事实证明，他们的看法是对的，但不全对，因为世上本就没有绝对的事情。<br />这时，我还在一家私营公司里打工，于是，白天上班，晚上就挑灯夜战，每晚不到12点不休息。<br />经过半年的复习，我参加了1997年元月的全国研究生入学考试，成绩出来，我专业课没问题，但数学才得了44分，毫无疑问，名落孙山。<br />这是一个打击，但对我并没有太大的影响。<br />这时，我小时住在隔壁的阿姨来到桂林，她说她女儿（我小时的玩伴，也姓杨）去年就考研了，但也同样没过，她原先在北京服装学院读本科，毕业分回广西柳州一个国企里，工作一年之后考研，没考上之后，她就把工作给辞了，专门跑到北京同学家中复习一年。97年考研她成功了。<br />得知这个消息，对我是个很大的鼓励。我想，她一个比我小的女孩都能成功，我为什么不行？我想办法与她联系上了，在后来的考研岁月中，她给了我极大的帮助，帮我买资料，帮我问成绩，写信给我，鼓励我坚持下去……<br />受人滴水之恩，当涌泉以报。<br />世上的人大都只会"锦上添花"，但只有"雪中送炭"才是最宝贵的。她就是我的"雪中送炭"人，她研究生毕业后嫁到青岛去了，断了音讯，但我心中永远记住了她的帮助。我决定，从今往后，如果我有能力帮助别人的，就一定要帮助人。这世界充满了太多不好的东西，我应该努力往其中添一点好的东西，哪怕显得多么微不足道</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />"土包子"的北京之行</p>
		<p style="font-size: 10pt; font-family: Arial;">中关村印象</p>
		<p style="font-size: 10pt; font-family: Arial;">刚好，1997年我大哥在北京中央美院进修美术，我决定明年继续考研，于是辞去了在一家私营电脑公司的工作，于6月底来到了北京，住进了大哥的宿舍中。6月到7月，我在北航学计算机维修，7月参加陈文灯老师的考研班，一直呆到9月中旬，我才回到桂林。<br />中央美院当时搬到了北京西北角的西八间房，我和大哥一起住在学生宿舍中。认识了不少来自全国各地的搞美术的大哥同学，我很喜欢和他们这些搞艺术的人在一起，看他们色彩斑斓，形象逼真的油画，和设计精巧的一些手工作品，是一种美的体验。与我们工科人相比，他们是另一种思维方式。<br />7月份，大哥要回桂林了。在回桂林前，我帮他和他的同学们去中关村电子市场一口气买了三台电脑，当时最红火的电子市场是中关村电子市场，就是现在北大太平洋电脑商场所在的地方。那时电子市场里熙熙攘攘，如此的红火，是我在广西所从未见到的也从未想到的。在大街上随处可见抱着台打印机，拎着个扫描仪的人，把电脑配件当成白菜一样卖，这就是我对闻名全国的"中关村电子一条街"的最初印象。<br />我到了中关村，见到了那些我非常熟悉的公司：北大方正，金山wps，江民科技……，见到了北京书堆积如山的书店，感叹这里真是一个知识的海洋，觉得亲身感受到了中国it业的脉博。<br />大哥回去后，我一个人留在北京，骑着辆破自行车逛了中国最有名的大学：北大和清华，北大风景如画的未名湖上处处荷叶飘香，清华平平展展的草坪展示一种平实坦荡的心胸。一墙之隔，校园内外，就是两种不同气氛，无名无状，却让我这个二十多岁没出过广西的土包子感受深刻。</p>
		<p style="font-size: 10pt; font-family: Arial;">"疯狂"的考研班</p>
		<p style="font-size: 10pt; font-family: Arial;">我参加的是暑期文登学校的考研班。中央财经大学那栋破败不堪的学四楼里，住满了来自全国各地的学生，和我住在一起的，一个是湖北的，一个是东北的，一个四川的，为了同一个目的，大家从天南地北聚到了一起，我当时真感到了一种"家"的感觉，原来这世界有这么多同路人，我不过是中国十几万考生中一名不起眼的"老生"罢了，但还不算是"范进"。<br />考研班的日子是"疯狂学习"的日子。<br />记得我们需要到北方交通大学的大礼堂去听人大老师索爱群的政治课，一千多人的大礼堂被挤得满满的，连过道上都坐了人。在老师的讲台前堆满了各式各样的录音机，足有一百多部，来自全国各地的莘荠学子拿着一芀笕诒本┳钊鹊?月，挥汗如雨地在记笔记！这段日子，我用去了7个笔记本！这种气氛，我以前在广西是从未见过的。我本来以为我已经够努力勤奋的了，到北京考研班一看，根本就不算什么。<br />陈文灯老师教的数学给我留下了最为深刻的印象，他上课不用讲稿，所有的例题全都记在他的脑里，随手就可以写出来，丝毫不差，还总结出一整套解题方法，让我大开眼界。我是见着了，原来一个人对本职工作可以精熟到这种地步！后面我还会谈到另一位老教授对职业可贵可敬的敬业精神，不敬业，就不是一个合格的劳动者。<br />我一直呆到身上没钱了才离开北京。这三个月花完了我工作几年的所有积蓄，却对我的影响是巨大的，中国什么地方最适合学习？最适合学计算机？在我看来，只有北京！<br />我下定决心，一定要到北京来学习计算机技术。<br />差点跳楼的致命打击</p>
		<p style="font-size: 10pt; font-family: Arial;">9月中旬我回到了桂林，开始准备第二年的考研。<br />但生活是不讲情面的，我想当然地认为经过了北京名师的指点，我去年就是数学没过，今年应该没问题了，但事实并不如此。<br />1998年的数学试题，突然有了一次很大的变动，这次数学考试特别难，题量还特别大，全国及格率仅7%，平均分为30多分。我现在将这次考试试题称之为"变态"的题目，出题的那帮呆在空调房里的教授们挖空心思出出来的题目，可把我给害惨了。我自认为心理素质够强了，但因为这场考试关系命运太大，在考场上我的手都是抖的，几乎晕倒，一道道的大题空在那儿做不出来，都象是在不断地讥笑我不自量力，又象是一张张面无血色的血盆大口，一张口就把我给吞下去了，连骨头渣子都不吐。<br />考完数学，我就知道我今年没戏了。原来一个考场有几十位考生，考完数学之后只剩下不到三分之一的人。我坚持着把后面的课腒纪辍Ｔ谀侵置髦尥銎疽恢中拍钪С抛乓岢值降椎氖笨蹋艺娌恢赖笔笔窃趺窗ね旰竺娴淖ㄒ悼慰际缘摹?br /&gt; 3月，成绩下来了，我的数学成绩让我差点去跳漓江了---13分！我从小学习勤奋努力，从没拿过这么低的分数。真是破纪录！当时真是灰心到了极点，准备放弃考研，到广东打工，找个地方浪迹天涯，自生自灭去，实在没脸在家呆了。<br />这个时候，我大哥劝住了我：你都考了两次了，我看来你就是数学差，其它课你都过线了，专业课还都是80多分，为什么不继续努力？集中精力把数学搞好就可以了。你现在放弃，就前功尽弃！<br />我这人笨，从小学东西就慢，这是一大弱点。但上天是公平的，他给你一个弱点的同时，也一定提供了让你克服这个弱点的方法。<br />我笨，但我好强，但我勤奋，但我坚持，人一之，我十之，笨鸟先飞，古已有之，古人可以做到，我为什么就不能做到？这事就这么收场？我不服，不甘心！于是，我下定决心再拼一次。<br />我现在没有工作，也不想再去找工作了，住在家中，就与堆积如山的书干上了。在关键时刻，年迈的父母无条件地支持了我，他们默默地承担了一切，让我有饭吃，给我一个安静的环境，让我去实现我的梦想。<br />我深深感受到父母的爱是多么的无条件！我一个二十五六的大小伙子，呆在家中吃闲饭，还让父母为我的前途操心，那种心灵的煎熬，现在想起来都有种想哭的感觉。男儿有泪不轻弹，只因未到伤心处！在此，我要深情地对我的父母说：儿子绝不会忘记你们的恩情，唯望两老保重身体，一定要等到看到我过上好日子的时光。<br />反思，走自己的路！</p>
		<p style="font-size: 10pt; font-family: Arial;">考研失败，我反复想，为什么我听了陈文灯传授的做题秘诀，反而考得更差了？别人为什么用陈老师的方法考出了好成绩蠢矗扛鋈说木咛迩榭霾煌淮嬖诳梢匀萌吮┏すαΦ摹拔淞置荏拧保诱饧轮形已У剑霾荒苊孕湃ㄍ孕爬砺邸：罄次叶孕矶嘞窒笥氤绷魅鏲mm热，设计模式，软件工程等理论都持有不同的看法，认为把西方的东西原样照搬是行不通的，不经过自己的大脑独立地思索，不经过实践的检验，不要相信任何东西！<br />从98年到99年1月，我断绝了一切外部联系，把自己关在了家中。我父母的工作单位是一个疗养院，全院加起来也就一两百号人，后山就是一个森林公园，空气清新，林木繁茂，大院里还有一个小山（是真山，不是假山，桂林的这样象竹笋似的山多了），山上修了个亭子，平时少有人来，真是一个闭门修行的好地方。<br />我每天到小山亭子上去学英语，背政治，桂林四季长青，我周围是青山绿竹，微风一过，树叶沙沙做响，我就在这里学起了战国时的苏秦。从春学到夏，再从夏学到冬，苦苦学了一年，这一年里，使我的心志得到了极大的锻炼，困难更加难以击倒我。后来我境况转好，生活中很多人觉得受不了的挫折，在我看来都不过是小菜一碟罢了。<br />桂林多奇山，秀美苍翠，风景四季如画。每当我学累的时候，总是看着这美丽的风景，赞叹祖国江山如画，感触人生之渺小，命运之无常！<br />大哥从北京带回了一台电脑，奔腾166，4.2g的昆腾大脚硬盘，当时不错的配置，把它送给了我用。我渴望了多久的东西终于到手了，我终于可以无限制地使用计算机了！我把电脑放在床前，伴它入眠。<br />我有时半夜会突然惊醒，想着目前的困境，浑身会出一身冷汗。电脑沉默不语，在一旁安静地陪着我。我看着那蓝幽幽的屏幕，心情非常复杂。<br />有了电脑也难过，我得抑制住自己强烈地想探索软件技术的欲望，强制自己把主要精力放在考研上。<br />整个考研英语大纲有5300多个单词，为了背下它们，我用vb编了一个背单词的小软件，每次可以分别显示中文或英文，并可以区分哪些单词没记住，下次复习。所有单词我都是用键盘一个字母一个字母地敲入的，每天早上一起床，先对着电脑背它半个小时。到考研结束，我一看，数据库中已有了两千多个单词。<br />这一年以来，我真是玩命，什么考研理论我都不信了，我就托人买了国家教委出的几本考试分析，就专门研綤佳惺蕴猓乙页鍪屎衔易约旱姆椒ɡ础?br /&gt; 考研数学考试分析500多页的书，被我翻来覆去地将历年考试试题做了三遍。党的十五大报告我至少背了一百多遍，我称之为背"语录"，真称得上是"倒背如流"，考政治时我把大段大段的十五大报告文字抄上去，居然得了75分！<br />发黄的本科高等数学和概率与数理统计，以及蓝色封皮的线性代数课本，都被我翻得不成样子。我觉得我就是基础太差，在这种基础之上，讲什么做题方法都是空中楼阁，一定要抓住"三基"（基本知识，基本方法与基本原理）。但我不得不悲哀地指出，我这些努力并未使我的数学能力有所提高，数学并不是这样学的，数学思维绝不是这样培养的。怎样学数学？得去问华罗庚与陈景润等数学大师！我至今数学还是不行。也希望有这方面经验的人能够教我，让我补上数学这一课。<br />生活总算给了我一次微笑。1999年考研，我数学得了60分，终于迈进了大学的门槛，可以打起背包上北京了。<br />我这人比较笨，不善于找到达到目标的最佳路线，但凭着牛劲钻下去，硬给我钻出了一条路。这条路能走通还带有一些侥幸的色彩，大家想必比我聪明得多，一定能找到更好的路，用更经济更聪明的办法达到目的，这是一种大智慧，是我所没有的。<br />这段经历对我个人的思想品质的影响是深远的。为什么这么说？为了考政治，我深入全面地了解了中国近现代史，我去盗版碟市场买了不少存有历史资料的光盘，从多方面来看中国历史，凡电视中有关历史的节目，我必看。我在这里尤其想说的是一个巨著——《毛主席选集》！经历过文革的每个家庭，哪家没有毛选？我家就有不止一套。毛主席选集一到四卷，发黄的书被我在这段时间通读了一遍。其中的经典文章更是被我看了一遍又一遍，赶上金庸的《射雕英雄传》了。越读越觉得毛主席之人真是数百年才出一人的大牛人，他的《湖南农**动考察报告》、《论持久战》等著作，其中体现出来的深刻洞察力与对中国国情的深入把握，其博大的心胸，为国为民的精神真叫我震撼！最终夺了天下，实在是中国社会的必然，当时她集中了多少中国最出色最优秀的人才，再加上毛主席这种不世出的大牛人领导，老蒋真与他不是一个水准的，想与老毛逐鹿中原，必败无疑！我成了毛主席的崇拜者，但绝不是盲从者。<br />说起来大家可能不信，我从毛选中得到了许多精神上的营养，更加乐观了。毛选，真是中国人巨大的精神财富！近年来有不少愤青指着毛主席晚年的失误全盘否定毛主席，在我看来真是狂妄无知，他们有几个真正了解毛主席？有几个真正客观地看过毛选？有几个有资格对毛主席做出评价? 把他们放回毛主席生存的那个民族危亡的时代，他们还会有这么多P放？！说不定最先当汉奸的就是他们。呵呵，不好意思，说粗话了。<br />闲话少说，回到正题。<br />回顾这段经历，我只能说是"具有中国特色的考研之路"。我感叹，中国的考试就是扼杀人性的东西，高考与考研尤其如此。我要是用这种精力去学计算机，一年半的时间，还有什么技术学不到手？但我没办法，现实逼着我去考这种我并不想考的试。中国考试之难我看全世界也不多见，我想，每年全国还有那么多的学生要参加这种考试，大量的人力物力与年青人的精力和时间都耗费在考试上了，而考试的内容与实际脱离那么远，真的有助于人才的脱颖而出？我看反倒是形成了一种应试教育，扼杀了年青人本来所具有的创造性，中国现在为什么出不了大师级的人物，应该反思中国的教育制度。<br />希特勒地堡与cih病毒</p>
		<p style="font-size: 10pt; font-family: Arial;">刚好我编的程序告一段落。于是就crazy地敲键盘，一鼓作气地把下篇写完了。心中有好多话一次就说个痛快。<br />看得越多想得越多我就越困惑，人啊，你活着到底是为了什么？又整天忙忙碌碌地追求些什么？我这十年，……我都不知道怎么说了！<br />大家自己看吧！<br />---------------------------------------------------------------------------------<br />实践人生<br />-------一个普通it人的十年回顾（下）</p>
		<p style="font-size: 10pt; font-family: Arial;">下篇 曲折的实践之路</p>
		<p style="font-size: 10pt; font-family: Arial;">1．希特勒地堡与cih病毒</p>
		<p style="font-size: 10pt; font-family: Arial;">99年4月，我来到北京参加研究生复试。复试完了之后就不回去了，我拿着一张光盘，里面刻着我用vb和authorware3.5编的一个cool 3d的教学软件，到处参加招聘会，开始了在北京的打工生涯。<br />说句实话，我心中真是一点底也没有。北京人才济济，我一个三流大学的毕业生，又不是计算机专业的，有人要我吗？<br />我在北京无依无K，没有任何一个亲戚在北京，住成了大问题。北京这地方，钱太不经花，生活费用太高，我四处寻找便宜的地方住。后来，我在北京化工大学对面的招待所中租了个床位，每晚20元，地下室。这个招待所的地下室非常大，每天回去的时候，都要走过长长的曲曲折折的通道，加上那昏黄的灯泡，每次我都有走进了希特勒地堡的感觉。地下室里潮湿阴暗，不见天日。地下室里人员很杂，什么人都有，永远没有一种安全的感觉，所幸的是我也是个穷光蛋，光脚的还怕穿鞋的？别人能呆我也能呆，唯一让我担心的是钱，没钱，在北京连流落街头都不够格，立马被收容去昌平筛沙。呵呵，我没这种经历，这是当时住一块的一个外地要考北京中医药大学的博士生说的（我俩居然住到了一个屋里，大家都没钱，只能挤地下室，只是他老兄晚上打呼，我可真受了不少罪）。<br />日子一天天过去，袋里的钱一天天少了，但工作还是没着落，心中越来越慌，除去学费，来京时父母给我2000元，大哥资助我的1000元就是我当时的全部资金（3000元在北京能呆多久？！）。我当时订了个计划，留下500元保底，打死都不能动，要K它作路费回家的。我当时说，一定得找到一家公司，再少的钱都干，只要有口饭吃，有张床让我睡我就满足了。<br />我一共应聘了四五家公司，最具传奇色彩的是到西单附近一家公司的应聘经历。那时，我带去了我的作品，公司项目经理要看，于是我给他们演示，很奇怪，程序一打开就死机，一连两台电脑都一样，末了，两台电脑都启动不起来了。用瑞星一查，cih病毒——那天正是4月26日！于是，cih破坏了电脑主板的同时，也无情地摧毁了我的就业机会。还算老板可怜我，没要我赔。其实我当时快到山穷水尽的地步了，真要我出钱，我可能连家都回不了啦。陈盈豪（cih病毒的作者），你小子这么的聪明做什么不行，偏要去做病毒，害人害已，弄得我连个饭碗也找不到，晚上回"希特勒地堡"，把这小子骂了无数次！<br />总算天无绝人之路，在我数着最后还剩余600元钱的时候，终于有一家公司要我了，做中小学教育软件，月薪1600。干了两星期，又给我在公司的仓库挪开货物，搭了个床位，我就在那住下了，庆幸再也不用到"希特勒地堡"里当冲锋队员了。每天下班后，我就睡在林立的大纸箱之中，如果来个地震，呵呵，我就埋在纸箱中了，休想爬得出来！</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />我干得非常努力，第一个月工资开出来，扣掉个人所得税，我拿了1500多元。你们不知道我拿到第一笔工资的感觉！这钱在很多人眼里简直不算钱，但对于一个没工作近两年，工作也一个月收入不到200的穷小子而言，就象陈佩斯小品中所演的："我王老五活了一辈子，还从没见过这么多钱啊！"。好笑吗？我一点也不觉得好笑。我只是心酸，我到了28岁才可以用自己的知识与技能养活自己，再不用依K父母和兄长的资助，才真正完全用自己的力量在社会上站起来，一个没有经济自立能力的人，只能是个不成熟的人，一个躺在父母身上的人，不是一个真正的男子汉！我当这样的孬种当了28年！<br />我找到工作后向家里写过一封长信，信中讲了我对父母平时不好意思说的很多心里话，当时，我父亲说，母亲接到信都哭了。 我刚拿到工资，马上打了个电话回家里告诉母亲，以缓解他们的焦虑，毕竟儿行千里母担心啊！父母有退休金，一再表示不需要我赡养，而我再这样不要脸下去，我还是人吗？我就是从那时候开始，下定决心，从今往后，再不向家中要一分钱！今后三年读书和生活的费用我一定要用自己的劳动来获取。<br />金钱带给我的激动就是在那段时间，温饱问题解决之后，金钱对我的诱惑就再没有了，哪怕让我一个月赚一万，给套房子给我，也不可能再给我带来幸福的感觉了，钱是重要的，但不能成为它的奴隶，家中不需要我负担，我一个人有吃有喝，干着我喜欢的工作，足矣！<br />我在那公司一直干到九月学校开学为止。我走的那一天，公司居然还开了个欢送宴会，老板封了500元的封包给我。我真是感动。我大学毕业后在社会上挣扎求生，得到的大都是冷眼与蔑视，社会终于认可了我的价值，我不是一个只知道吃饭的废物！<br />1999年9月9日上午9点，在这个最多9字的时刻，我到学校报道来了，放下行李，我坐在分配给我的床上，心中终于踏实下来。<br />现在，我在北京终于有一张属于我的床了，一张真正属于我的床了，终于有个地方可以让我安稳地睡觉了。没有这段经历，我怎么体验到"安居乐业"这一个词的真实含义！个人如此，国家要做到，中国要做到，更难！<br />2．编程生涯<br />读研两年半的时间，我四处打工，这两年半我至少在七八家公司做过，编了十几万行代码，为自己赚了一台电脑，两部手机（丢了一部），还有读研期间的所有费用，实现了我的目标：没向家里要一分钱。<br />我水平不高，但在打工过程中，发现许多中国软件公司的水平更菜！<br />2000年暑假，我参加一个商品软件的开发，搬到了北大燕北园的一个宿舍，在那儿搞封闭式开发。在这个项目采用vb6开发，主力程序员除我之处，还有一个华北电力大学的研究生。大家都没开发商品软件的经验，没经过正式的设计，就匆忙编码了。我曾经想采用分层的系统架构，但遭到另一位程序员的反对，争吵没有结果，老板也不能做决定，结果各行其是。现在看起来，那时真是太菜了，任何一本软件工程书都会指出这种做法是不对的。<br />我们直接就热火朝天的干了起来，那位华北电力大学的老兄，真让我佩服，他可以在一个sub过程中写上2000行代码！我觉得奇怪，为何他能写这么多的代码？一看，顿时我晕倒，他居然将每个控件的left,top,width等属性都用代码来设定！想想这样的程序，调试时光单步执行就需要按多少次f8键！<br />我们在电脑旁边搭了个行军床，每天都是干到早上6点才睡，12点吃中饭，然后又是一个通宵。当时整个工程只有一个类模块，被我用于封装访问数据库的ado数据引擎，这是整个工程中唯一一处用到了最简单的面向对象技术的地方，然后，我写了近十个bas公用模块，每个模块代码规模都有一两千行，还有十几个窗体，每个窗体中都塞满了事件驱动的vb代码，整个软件应该有10万行代码，我一个人在此期间至少就写了3万多行vb代码。程序的主处理流程我甚至用ado与dao写了两套！<br />现在想起来，我们当时根本就不知道面向对象为何物，更不理解许多对软件开发至关重要的理论，就凭着一种热情。在这段痛苦的开发经历中，我不仅精熟了vb，而且从中学到了很多。现在再开发同样功能的东西。我至少可以砍掉2/3的代码。怎么学都不如从失败中学得多。<br />后来我总结vb程序员的三个境界：<br />（1）所有代码都只放在窗体文件中的，属于菜鸟级，他们只会从面板上拖控件，设置属性，然后再给事件编码<br />（2）工程中有bas模块的，属于中间级，他们已意识到有大量的代码是重复出现的，应该将其抽取出来作为公用模块<br />（3）工程中有cls模块的，属于高手，他们已掌握了面向对象的思想，并能应用这种思想来解决实际问题<br />正是这次开发经历，促使我反思：到底如何开发软件？我个人可以用vb完成各种各样的功能，为什么凑在一起就会那么困难？更正一个bug为何那么难？为什么一个看似简单的软件，要拖半年的时间还看不到结束的日子？<br />九月，研究生要开题，我自拟了个课题：软件体系结构设计。我决心弄明白，好软件到底是怎么做出来的。<br />我放下了vb，开始研究c++，原来学过vc，但没学会，就直接从c++ builder入手。borland公司的vcl类库让我大为叹服，很快就迷上了它，为此连带学了delphi，并参与了一个delphi项目。给我真正震撼的是《设计模式》这本书，看了才知道，原来好软件是这么设计出来的！在此，我强烈推荐所有有一定编程经验的程序员一定要看这本书！<br />一边学习理论，一边可没忘记我没经济来源，于是又四处打工，接一些小项目与小模块来赚些生活费，国内一家横跨家电与软件的著名公司是我打工期间去过的最大的公司。但无论什么公司，都给我一种感觉——烂！公司中充满了对员工的剥削与不尊重，对软件开发这一事物的错误认识，管理混乱。<br />我没机会去外企，技术水平不到，别人不要我 ?，但我所见到的软件公司，我敢说没一家能做出世界一流的软件！<br />我上的研究生课程也让我失望，整个就是本科教育的再版。经过高考与考研两次重大考试，我对考试已是深恶痛绝，但读研期间仍要考试，而且是闭卷！我就不知道我去背那些条文对我的研究与学习有何帮助？2000年7月当我考完最后一门，终于大松一口气，我终于摆脱了考试的压迫，可以在剩余的一年半中真正搜索我渴望已久的软件技术了。这年，我29岁。<br />悲哀吗？一个中国的程序员要到29岁才可以真正自由地学习想学的东西！<br />我开始研究面向对象理论，看了大量的书，每天都在实验室学习到深夜12点，天天上网，csdn成了我最常去的网站。<br />随着我对软件技术的了解越多，就越深刻地感到国内与国外技术水平的差异是如此的巨大，巨大得甚至有让人绝望的感觉。同时，在北京这个中国软件人才最集中的地方，我也见到了许多牛人，一个清华的本科学生，做程序员可以拿到一个月12000元的工资，一个北大的计算机系研究生，一毕业就到外企，一个月一万多收入，每年发16个月工资！干了两年就开了自己的公司。我看到了一个北方交大的本科生作品，在半年的业余时间里，用delphi写了十几万行代码，他甚至在代码中嵌入汇编，自行编写数据存取引擎读写foxpro，速度超快！软件中有一个计算公式解析模块，他用编译原理理论居然做了一个小型的公式解析器，就象c++编译器检查c++程序一样，不仅可以判断是否公式正确，而且给出的出错信息还相当准确！其基本功之扎实，水平之高让我望尘莫及！中国优秀的人才真还是不少的！在精英集聚的北京，面对着博大精深的软件科学，我深感自身的渺小。<br />但我毕竟是K自己奋斗出来的，我并不自卑，这世界需要牛人，同样需要大批合格的劳动者，我成为不了牛人，但我作一名程序员是合格的。<br />时间过得飞快，一年半根本就不算时间，马上就要毕业了，学习的成绩如何，要到社会上去竞争了，让社会考场来决定你是否及格。<br />3．毕业求职</p>
		<p style="font-size: 10pt; font-family: Arial;">98级的研究生是it业最后辉煌的回光反照。当时，各大公司都发了疯似的要人，象华为，当时是来者不拒。计算机专业的研究生是一抢而光，本科生也供不应求。2001年毕业的我的师兄师姐们，平均每个人手头都至少有两三个offer，谈的工资没有低于每月6000的，许多人去了外企，工资在8000~10000每月的也有。真是毕业生的黄金时间。<br />但好景不常在，911事件我看来好象成了分水岭，911之后，整个it业急刹车，就业形势急转直下，各大公司都在消化去年吃得过饱的胃口，我形容是大家都吃坏了胃，再也不可能有我师兄师姐们的风光了。虽然时间相隔仅大半年。<br />从10月开始，11月和12月，我几乎是在招聘会与公共汽车上渡过的，北京东南西北地去面试，上午在上地，下午可能就要跑到朝阳区，疲于奔命。<br />在找工作过程中，我良好的心理素质与丰富的编程经验起到了很大的作用，并没有遇到很大的困难，就先后有几家公司表示要我。<br />其中我想说的有两家公司。<br />一家是台湾公司，应该说他们做得是不错的，但我非常反感他们那种自认为高于大陆人的那种优越感，而且待遇也不高。面试之后，回来感觉很不好。当时台湾是民进党上台主政，我就称之为"民进党"看不起""（虽然我不是党员，但我们都是中国人，都希望中国能强大，让她的人民能挺直腰杆）。<br />我想：我们大陆确实是不如台湾发达，难怪别人看不起我们，这世界势利得很，社会如此，国家亦然。但我中华960万平方公里的国土，13亿人口，难道要依K一个小小的岛屿来撑门面？难道除了台湾公司，我就无处可去了？虽然改变不了什么，但我决定绝不去台资和日资的公司工作（日本人我更不喜欢，但我认为他们做事实在优秀，我们一定要向日本人学习）！在这种公司呆着，不爽！同时，我们的确也得争气些，这世界只尊重强者。<br />另一家是个很不错的民族软件企业，想要我，其老总专门找我去面谈了一次，希望我能到他的公司工作。这位老总白手起家，能在五六年的时间内由几个人发展到300多人，当时，是中国这个领域软件市场占有率最高的公司，我非常佩服，他为人也很好，并表示可以给我每月比其他研究生多加1000元工资，而且希望锻炼一两年之后我能够带领一个团队来开发产品，并负担我毕业所需交纳的各种费用。在就业不景气的2002年，对我一个30岁的技术水平有限的老程序员如此看重，真叫我感动。虽然我最后还是没去，但我仍然对这个公司充满了好感。一个软件企业最重要的是什么？是对人的尊重，没有这点，可以断定，这个公司长不大。<br />我为什么没去软件公司？放弃有可能在几年之后年薪突破10万的收入？是因为我已有了更想做的事，我想当老师！<br />我自己是从自学的路上走过来的，其中的艰辛历历在目，无人指点，我走了多少弯路？中国还有多少是象我这样的年轻人无人指点的？我幸运能爬出来了，因为我至少还能有饭吃，比我条件更差的，比如农村的孩子，可能就被生活的压力所淹没了。我个人的力量很微弱，技术也有限，但我自认为至少是一名合格的程序员，如果能培养出一大批达到我的水平的学生，他们毕业后成为合格的程序员，中国软件的根基就会更扎实，如果更能有一批远远超过我水平的学生出来，中国软件就有希望了。软件是什么？软件以人为本！<br />人生追求什么？金钱？我很缺钱，但不可能把金钱作为我的目标，我希望我能够成为一个对社会有所贡献的人，能够获得心灵的充实，于是，我选择了留校。</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />4．对教育的反思与教书生涯<br />2002年下半年，我参加了北京高校青年教师岗前培训。一位杜教授的两堂课让我印象深刻，其中两句话让我深深震动：<br />第一句话：我是一个教书匠，教书匠好啊，好就好在"匠心独运"！<br />第二句话：做什么工作都要达到变魔术的境界！<br />是的，作为一名教师，就必须起到一个传声筒与放大器的作用，将人类最聪明的人探索世界所得到的知识予以拓宽发展，以便让更多的人能够掌握这些知识并进而应用于实践，从而推动人类的不断进步。<br />作为一名计算机专业的教师，就要努力把先进的计算机技术以尽可能高的效率传授给广大的学生，引导他们直接面对真实的软件世界，而不是向他们硬灌各种各样的理论知识，强迫他们去死记硬背以应付考试。<br />我是一个小人物，才低学浅，但我真的认为高校计算机教育存在严重的问题。我在打工期间的开发经历，以及阅读国外相关资料的时候，发现学校中教的和社会上用的差得太远！都已经是什么时代了，许多大学还设立foxpro课程，难道就不能直接用现代主流的数据库如oracle，sql server，哪怕是access也好，来讲授数据库知识？还有所谓的计算机等级考试，呵呵，过了三级学生的我见过不少，但他们真正对软件，对计算机又理解多少？<br />在中国甚至于升职称也要考计算机，我看了一本职称计算机考试教材，里面几乎原样照搬计算机原理课程中的相关章节，弄得我给搞艺术的大嫂讲了一个小时的二进制与八进制、十六进制的转换方法，她还是弄不太清。我都泄气了，对啊，他们搞艺术的，有必要去分清二进制的10与十进制的2有何分别吗？他们八辈子也用不上。但是考试用得上，呵呵，又是中国特色。<br />拿c++来说，我讲过c++课，许多的国内教材对c++语法下了大功夫，却对体现了c++精华的stl只字不提，对代码背后所体现的软件开发思想与方法更是视而不见，我用c++也编过不少程序了，说句实话，我用到的特性不到c++的三分之一！于是就出现了这种怪现象，许多学生考试可以拿八九十分，给他一个简单的实际问题他却不知如何下手！<br />还有uml，现在好象很火的样子，我们读研时就开了这门课，讲句实话，当时这门课我就没听懂，可后来我尝试着用c++用面向对象的方法来编程序，然后，由代码倒推回uml类图，一下子就明白了，原来uml只不过是一种描述面向对象系统的符号罢了，如果学生没进行过真正的oop，那就是为了学uml而学uml，根本就本末倒置。<br />还有软件工程，我的感觉，一个人如果没写过一万行以上的程序，他看软件工程书就同看政治书差不多，每句都对，呵呵，就不知道为什么对。我完成了那个几万行的vb程序之后，再回过头看看理论，真是句句是真理！每个理论背后都是大量实践经验的总结。<br />回想我做软件的体会，我发现所有的知识都是一个完整的体系，根本就无法区分哪些知识是本科的，哪些知识是研究生课程。于是，一种想法产生了，我主讲程序语言类的课程，那我就直接以真实的软件开发过程为主线，实践中需要什么我就讲什么。讲c++/，我就抛开了指定的教材，c++我讲了stl，我讲了ooad，两者我都讲了用rose进行双向工程，引导学生去学uml，一开始就用uml去描述自己开发的程序，何必浪费大量的时间去学结构化的编程方法？<br />我现在简直成了面向对象技术的布道者，我下学期即将开设ooad基础选修课，从实际项目中抽取典型的案例，讲uml，讲rose，讲设计模式，讲软件体系结构，例子代码横跨c++/和.net下的开发语言（c#和vb.net），这对于我一个技术水平有限公司的董事长而言，实在有点不自量力，我鼻子上才插上几根葱，就想装大象？但我想，如果我能成功地激发出哪怕1%的学生的兴趣，能引导他们走向我认为是正确的方向，能启发他们思考，能直接面向真实的软件开发活动而不是学校的考试，就是我的成绩。我现在正在看引进的原版书籍---《设计模式解析》，时时击节赞叹！《设计模式》经典但难懂难用，而《解析》一书的两位作者既有丰富的从业经验，又对ooad进行了深入的思索，真知灼见时时展露于书中，我现在刚看了这本书的80%，基本上可以用一个成语来描述这部书：深入浅出！<br />要做到深入浅出谈何容易！只有同时具备技术专家与文学作家素质的人才能做到！<br />反观我们国内的大量教材，还有大量的垃圾论文（包括硕士，博士的，本科的就算了，我看绝大部分根本不能称之为论文），全都是"浅入深出"，作者自己都未必明白，就东拼西凑，摆出个样子吓人。本来完全可以用大白话三言两语讲清楚让人明白的道理，有人专门要绕一大圈，专挑用高深的数学公式来表达，唯恐别人容易理解，显得他水平不高！呵呵，什么东西一沾上"数学"，立马身价百倍。我就听过一个北师大的一个在读博士说过：如果一篇博士论文中没有一个数学公式，根本就不算是博士论文。这句话对不对，大家可以多思索。我数学不好，没资格讨论数学，我的直觉：数学是工具，但如果为了发表论文等目的而故弄玄虚，为数学而数学，是不合道理的。中国的学术水平与现状，大家都心知肚明，不用我废话了。<br />现在每年都毕业大批的计算机专业学生，可其中真正具备扎实根基的可以很快胜任工作的我看只有5%（95%的学生不要扁我，不同意就当我在说胡话，我很瘦的，一扁就没了?）。多年以来，我国高校计算机教育是按照计算机科学研究者来培养的，可事实上，有多少学生能从事计算机方面研究的能力？我看应分流，80%的学生按工程师方向来培养，20%的学生按研究者方向来培养，而且应大幅减少必修课的数量，计算机领域太深太广，样样都想教给学生，反而成了夹生饭，一个想从事硬件设计的学生和一个想从事软件开发的学生，能给他们一样的饭吃吗？学校应提供各种条件和资源去引导学生，激发学生的创造性与主动探索性，让他们去尝试，去发现自己的长处，最终找到最适合自己的发展方向。不这样做，中国软件后继乏人，没希望。<br />5．实践第一<br />2002年下半年，我和一个朋友去了北京郊区的一家杂志社，看到的情形让我震惊：在信息产业最发达的北京，这家杂志社还用人工查对杂志订单和款单，看着那按省来登记的几大本厚厚的客户登记本，工作人员需要手工来在其中查找相应的信息。这样的工作效率，这样的行业信息化水平！北京如此，全国又如何？<br />从这件事上，我看到了中国软件业的另一方面。一方面我们没有核心技术，另一方面，已有的技术又根本没推广没用好。追踪世界先进水平，对于我等这种水平的人来说，确实勉为其难，但将已有的技术用于解决实际问题，却是我们可以做的。如果中国各行各业都真正能通过进行信息化而提高生产效益，那中国不就从根本上强大起来了吗（象印度，it一枝独秀，其他行业没有起色，我称之为跛足的国家，绝不能成为世界强国）？在扎实的社会基础之上，软件业不就有了更大的市场与发展潜力？中国许多行业的信息化水平非常低，而且中国地域广大，发展非常不平衡，有些地方信息化水平甚至为0！努力推动行业信息化，是我们这一代软件开发者的责任！而追赶国外先进水平，恐怕就不是一代两代程序员可以达到目标的，需要长期的努力。作为一名软件开发者，只能脚踏实地，哪怕你只做一个小小的mis产品，也要尽力把它做好来。<br />于是，我开始了期刊发行系统的开发，这完全是自发的，没有任何资金投入，只有一种热情在支撑。我开始选择c++ builder开发，做了几个月，完成了第一个版本，但我发现，我找不到足够水平的c++程序员进行合作开发，而且整个一个exe文件，在体系结构设计上虽采用了分层分块的设计方案，但却是源代码级别的，要拆分成com组件难度太大，不是一个人能完成的，于是中途流产。<br />2003年3月，我开始系统地学习.net，我吃惊地发现，我原来想在c++中实现的许多功能，比如对象串行化为xml，在.net中已有现成的类可用，.net更把oo的功用发挥到了极致，它的混合语言开发，它的反射机制，它的新的自识别的软件组件，以及强大好用的开发环境vs.net，都让我惊叹微软对开发者遇到的困难的深入把握，相比用c++开发，至少可以提高1/3的开发效率。于是一个新的想法产生了，我要把以前的产品用.net重写，利用.net强大的组件模型，将设计模式理论推广应用到组件级别，通过xml和反射机制建立一套可动态装配的软件生产流水线，实现象dell直销pc那样的软件动态装配直销。只要建立好灵活可不断重构的系统架构，配以对业务领域的深入分析，逐步建立功能强大的业务组件仓库，就可以实现软件系统的动态装配。说干就干，我用vb,net重写了原先用c++编写的系统，将原先的一个exe变为十几个dll，而且这些dll还会随着发展而不断地分裂，也有可能重新组合，利用refractoring（重构）不断进化，最终形成一整套完备的行业软件组件库。做软件关键因素是变化，只有适应变化的系统才是有生命力的。<br />我用两个月的时间大体上弄清了.net平台下的主要类库，然后又用两个月的时间再次重新实现了期刊发行系统的c++版本的全部功能，到8月份我写这篇文章之时，第一个产品里程碑已经完成。同样的，除了需求是由另一个合作者去搜集的之外，几乎又是全部由我一个人包揽了所有的系统设计及编码工作！ <br />毫无疑问，我自觉得新系统要比老系统可维护性强得多，真正实现了彻底的全组件化系统开发，计划再有一个月的界面美化，改正bug，引用多线程提高运行效率，优化系统结构，就可以提供给用户试用了。市场如何，难说难测。<br />在开发过程中，我再次感到巨大的挑战，不光是技术上的，更是管理上的。人才是我最头痛的问题，没有一流的人才，哪来一流的产品？我们找不到足够水平的程序员一起合作（牛人哪屑于做这样一个小儿科的产品？）我们要走的路还很长。也许我们开发的产品是失败的，但我从来就没指望能用这赚钱，我只是尽一个软件开发者的责任而己，成败已不重要！人生不尝试，怎能体现人活着的价值？<br />结束语 永无止境的软件之路<br />1．辛酸与苦辣<br />做软件开发很苦的，技术进步如此神速，每个软件开发者都得不断地学习以跟上发展的步伐。有时我常想，何苦呢？我现在在大学中混，怎么样不能混下去？为什么要做这些吃力不讨好的事？我投了十年的时间去学习电脑，却最终发现自己不过中人之资，离顶峰远之又远。古语云：三十而立。我今年32了，仍是孤身一人，看看周围的同学，他们的小孩都差不多上小学了！许多都有了自己的房子和车子，而我到现在才开始申报中级职称，还挤在集体宿舍中，望着北京高昂的房价而叹息。现在社会越来越功利了，看着象我这样的穷光蛋，看着由于长期面对电脑缺少锻炼而瘦弱的身躯，又有哪个女孩愿意嫁过来受苦？<br />软件人的生活很苦，压力很大，我认为是拿青春赌明天。就是在这种恶劣的开发环境中，还有许多业外人士指手划脚说程序员如何如何，还有太多的公司只顾压榨程序员的劳动，缺乏对程序员基本的尊重，怎不叫人寒心？<br />"三十而衰"，这句本不应该流行的话居然成了中国软件人员的流行语。中国程序员的悲哀！<br />2．无止境的追求<br />人类已进入信息时代，计算机技术几乎每隔半年就有一次大的变化，我现在又面临着这样的抉择：今后的路如何走？<br />北大的教师聘任制度的改革一石激起千层浪，说明了中国高校的改革势在必行。我是欢迎这种变化的，虽然到时我可能会下岗。但人生中总会遇到各种各样的挑战，只要你不倒下爬不起来，就有希望。<br />我想我必须再次让自己有个提升，要从小事做起，但做小事则绝不能成为最终的目标，也许，不远的将来，我会走出国门，到世界软件技术最发达的地区去汲取丰富的养份。今后的路怎么走，我还在摸索之中。<br />3．人生无悔<br />人生年华如水，时光无情。在过去的岁月中，我尽了自己的力，回顾往事，我可以说：过去的事只有遗憾，却没有后悔。如果给我再一次选择职业的机会，我还会再次选择软件！<br />再过10年，到2013年的时候，我也许会再次写一篇人生的十年回顾，到那时中国的软件会如何？中国软件的明天K你我这些普通人去扎扎实实地去工作来支撑！少发些牢骚，多做些实事，中国软件才会有光辉的明天。你我共勉！</p>
		<p style="font-size: 10pt; font-family: Arial;">--------------------------------------一个老程序员的心理话<br />完成于 2003-8-3 北京</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br />2003-8-3中午14：33,在我的弹指神功之下，我写完了这近两三万字的个人自诉。一点也不累，回想过去的种种感触，仍然身在其中。<br />楼上一位兄弟说想看我的爱情故事，但人生不是小说，没有什么浪漫的，我只能让你失望了，我是孤单地在人生之路上走着，我就是这样的一个带着点悲剧色彩的人。<br />如果有人能有这上中下三篇文章耐心看完，我会谢谢你。如果有人能指点我，我感激你。<br />好了，我去休息了，生活是一天天过的，不是吗？ <br /></p>
<img src ="http://www.cppblog.com/erran/aggbug/34121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:18 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>__declspec(dllexport)与.def文件</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34120.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34120.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34120.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34120.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34120.html</trackback:ping><description><![CDATA[<font size=2>
<p><br><strong>__declspec(dllexport)与.def文件</strong><br><br><br>在VC++中，如果生成DLL可以不使用.def文件。只需要在VC++的函数定义前要加__declspec(dllexport)修饰就可以了。但是使用__declspec(dllexport)和使用.def文件是有区别的。如果DLL是提供给VC++用户使用的，只需要把编译DLL时产生的.lib提供给用户，它可以很轻松地调用你的DLL。但是如果DLL是供VB、PB、Delphi用户使用的，那么会产生一个小麻烦。因为VC++对于__declspec(dllexport)声明的函数会进行名称转换，如下面的函数： <br>&nbsp;&nbsp;&nbsp;&nbsp;__declspec(dllexport) int __stdcall IsWinNT() <br>&nbsp;&nbsp;&nbsp;&nbsp;会转换为IsWinNT@0，这样你在VB中必须这样声明： <br>&nbsp;&nbsp;&nbsp;&nbsp;Declare Function IsWinNT Lib "my.dll" Alias "IsWinNT@0" () As Long <br>&nbsp;&nbsp;&nbsp;&nbsp;@的后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换，就要使用.def文件方式。 <br>&nbsp;&nbsp;&nbsp;&nbsp;EXPORTS后面的数可以不给，系统会自动分配一个数。对于VB、PB、Delphi用户，通常使用按名称进行调用的方式，这个数关系不大，但是对于使用.lib链接的VC程序来说，不是按名称进行调用，而是按照这个数进行调用的，所以最好给出。如：<br>EXPORTS&nbsp;<br>test @1&nbsp;<br><br>&nbsp;&nbsp;vc的dll，delphi调用的方法：<br><br>////K9RtExpr.h<br>extern "C" __DECDLL <br>unsigned int _stdcall K9RtSysInterrupt(int nInterruptTag);<br><br>extern "C" __DECDLL <br>unsigned int _stdcall K9RtSysExprm(unsigned int nModuleTag, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float fTimeout,&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void * pTestPar,&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void * pResultPar&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br><br>// K9RtExpr.cpp<br>#include "K9RtExpr.h"<br>#include "RtCtrl.h"<br>extern "C" __DECDLL <br>unsigned int _stdcall K9RtSysInterrupt(int nInterruptTag)<br>{<br>&nbsp;return CRelayTestControl::Instance()-&gt;InterruptTest(nInterruptTag);<br>}<br>extern "C" __DECDLL <br>unsigned int _stdcall K9RtSysExprm(unsigned int nModuleTag, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float fTimeout,&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void * pTestPar,&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void * pResultPar&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>{<br>&nbsp;return CRelayTestControl::Instance()-&gt;RelayTest(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nModuleTag, fTimeout, pTestPar, pResultPar);<br>}<br><br>///K9RtExpr.def<br>LIBRARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "K9RtExpr"<br>DESCRIPTION&nbsp; K9RtExpr Windows Dynamic Link Library'</p>
<p>EXPORTS<br>K9RtSysInterrupt<br>K9RtSysExprm<br>&nbsp;&nbsp;&nbsp; ; Explicit exports can go here<br><br><br>//delphi&nbsp;&nbsp; 调用文件 <br>unit InterfaceFunc;</p>
<p>interface</p>
<p>uses<br>&nbsp;&nbsp; UnitData,Types;<br>&nbsp;&nbsp; <br>function K9RtSysExprm(nModuleTag:integer&nbsp; ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uTimeout:integer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;pTestPar:Pointer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;pResultPar:Pointer) : Integer; stdcall;</p>
<p>function K9RtSysInterrupt(nInterruptType:Integer) : Integer; stdcall;</p>
<p>implementation<br>const DLLPATH&nbsp; = 'RtBsExpr.dll';<br>function K9RtSysExprm; external DLLPATH&nbsp; name&nbsp; 'ExperimentRelayTest';<br>function K9RtSysInterrupt; external DLLPATH&nbsp; name 'InterruptRelayTest';<br><br>end.</p>
</font>
<img src ="http://www.cppblog.com/erran/aggbug/34120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 17:01 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：C++类库介绍</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34119.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 08:42:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34119.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34119.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34119.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34119.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34119.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;">原文：<a href="http://hi.baidu.com/chplj/blog/item/08d8f6368def16310a55a931.html">http://hi.baidu.com/chplj/blog/item/08d8f6368def16310a55a931.html</a><br />作者：<br /><br /><strong>C++类库介绍</strong><br /><br /><br />再次体现了C++保持核心语言的效率同时大力发展应用库的发展趋势!!在C++中，库的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了设计库来扩充功能要好过设计更多的语法的言论。现实中，C++的库门类繁多，解决的问题也是极其广泛，库从轻量级到重量级的都有。不少都是让人眼界大开，亦或是望而生叹的思维杰作。由于库的数量非常庞大，而且限于笔者水平，其中很多并不了解。所以文中所提的一些库都是比较著名的大型库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">
				<strong>标准库 </strong>
		</p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年，直到标准的出台才正式定型，但是在标准库的实现上却很令人欣慰得看到多种实现，并且已被实践证明为有工业级别强度的佳作。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">1、 Dinkumware C++ Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考站点：http://www.dinkumware.com</p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">P.J. Plauger编写的高品质的标准库。P.J. Plauger博士是Dr. Dobb's程序设计杰出奖的获得者。其编写的库长期被Microsoft采用，并且最近Borland也取得了其OEM的license，在其C/C+ +的产品中采用Dinkumware的库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">2、 RogueWave Standard C++ Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考站点：http://www.roguewave.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个库在Borland C++ Builder的早期版本中曾经被采用，后来被其他的库给替换了。笔者不推荐使用。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">3、SGI STL </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考站点：http://www.roguewave.com/<br />　SGI公司的C++标准模版库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">4、STLport </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考站点：http://www.stlport.org/<br />　SGI STL库的跨平台可移植版本。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">准标准库——Boost </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Boost 库是一个经过千锤百炼、可移植、提供源代码的C++库，作为标准库的后备，是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起，在C++社区中影响甚大，其成员已近2000人。 Boost库为我们带来了最新、最酷、最实用的技术，是不折不扣的"准"标准库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Boost中比较有名气的有这么几个库： <br /><br />　Regex <br />　正则表达式库 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Spirit <br />　LL parser framework，用C++代码直接表达EBNF </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Graph <br />　图组件和算法 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Lambda <br />　在调用的地方定义短小匿名的函数对象，很实用的functional功能 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">concept check <br />　检查泛型编程中的concept </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Mpl <br />　用模板实现的元编程框架 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Thread <br />　可移植的C++多线程库 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Python <br />　把C++类和函数映射到Python之中 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Pool <br />　内存池管理 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">smart_ptr <br />　5个智能指针，学习智能指针必读，一份不错的参考是来自CUJ的文章： </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Smart Pointers in Boost,哦，这篇文章可以查到，CUJ是提供在线浏览的。中文版见笔者在《Dr. Dobb's Journal软件研发杂志》第7辑上的译文。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Boost 总体来说是实用价值很高，质量很高的库。并且由于其对跨平台的强调，对标准C++的强调，是编写平台无关，现代C++的开发者必备的工具。但是Boost 中也有很多是实验性质的东西，在实际的开发中实用需要谨慎。并且很多Boost中的库功能堪称对语言功能的扩展，其构造用尽精巧的手法，不要贸然的花费时间研读。Boost另外一面，比如Graph这样的库则是具有工业强度，结构良好，非常值得研读的精品代码，并且也可以放心的在产品代码中多多利用。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考站点：http://www.boost.org（国内镜像：http://www.c-view.org/tech/lib/boost/index.htm） </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">GUI </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">在众多C++的库中，GUI部分的库算是比较繁荣，也比较引人注目的。在实际开发中，GUI库的选择也是非常重要的一件事情，下面我们综述一下可选择的GUI库，各自的特点以及相关工具的支持。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">1、 MFC </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">大名鼎鼎的微软基础类库（Microsoft Foundation Class）。大凡学过VC++的人都应该知道这个库。虽然从技术角度讲，MFC是不大漂亮的，但是它构建于Windows API 之上，能够使程序员的工作更容易,编程效率高，减少了大量在建立 Windows 程序时必须编写的代码，同时它还提供了所有一般 C++ 编程的优点，例如继承和封装。MFC 编写的程序在各个版本的Windows操作系统上是可移植的，例如，在 Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。但是在最近发展以及官方支持上日渐势微。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">2、 QT </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.trolltech.com<br />Qt 是Trolltech公司的一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展，并且允许真正地组件编程。自从1996年早些时候，Qt进入商业领域，它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是流行的Linux桌面环境KDE 的基础，同时它还支持Windows、Macintosh、Unix/X11等多种平台。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">3、WxWindows </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.wxwindows.org/</p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">跨平台的GUI库。因为其类层次极像MFC，所以有文章介绍从MFC到WxWindows的代码移植以实现跨平台的功能。通过多年的开发也是一个日趋完善的 GUI库，支持同样不弱于前面两个库。并且是完全开放源代码的。新近的C++ Builder X的GUI设计器就是基于这个库的。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">4、Fox </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">开放源代码的GUI库。作者从自己亲身的开发经验中得出了一个理想的GUI库应该是什么样子的感受出发，从而开始了对这个库的开发。有兴趣的可以尝试一下。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.fox-toolkit.org/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">5、 WTL </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">基于ATL的一个库。因为使用了大量ATL的轻量级手法，模板等技术，在代码尺寸，以及速度优化方面做得非常到位。主要面向的使用群体是开发COM轻量级供网络下载的可视化控件的开发者。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">6、 GTK </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://gtkmm.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnome这样的杀手应用。而GTK就是这个库的C++封装版本。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">网络通信库</p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">ACE </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.cs.wustl.edu/~schmidt/ACE.html <br />　ACE网络编程开发论坛：http://www.acejoy.com</p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">C+ +库的代表，超重量级的网络通信开发框架。ACE自适配通信环境（Adaptive Communication Environment）是可以自由使用、开放源代码的面向对象框架，在其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++ 包装外观（Wrapper Facade）和框架组件，可跨越多种平台完成通用的通信软件任务，其中包括：事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通信、共享内存管理、消息路由、分布式服务动态（重）配置、并发执行和同步，等等。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">StreamModule </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.omnifarious.org/StrMod/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容易，而不是用同步的外壳包起异步的本质。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">SimpleSocket </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://home.hetnet.nl/~lcbokkers/simsock.htm </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个类库让编写基于socket的客户/服务器程序更加容易。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">A Stream Socket API for C++ <br /><br />　参考网站：http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">又一个对Socket的封装库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">XML </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Xerces </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://xml.apache.org/xerces-c/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Xerces-C++ 是一个非常健壮的XML解析器，它提供了验证，以及SAX和DOM API。XML验证在文档类型定义(Document Type Definition，DTD)方面有很好的支持，并且在2001年12月增加了支持W3C XML Schema 的基本完整的开放标准。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">XMLBooster </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.xmlbooster.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个库通过产生特制的parser的办法极大的提高了XML解析的速度，并且能够产生相应的GUI程序来修改这个parser。在DOM和SAX两大主XML解析办法之外提供了另外一个可行的解决方案。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Pull Parser </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.extreme.indiana.edu/xgws/xsoap/xpp/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parser，这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Xalan </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://xml.apache.org/xalan-c/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Xalan是一个用于把XML文档转换为HTML，纯文本或者其他XML类型文档的XSLT处理器。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">CMarkup </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.firstobject.com/xml.htm <br /><br />　这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在DOM和SAX之外寻求一点灵感。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">libxml++ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">http://libxmlplusplus.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">libxml++是对著名的libxml XML解析器的C++封装版本 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">科学计算 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Blitz++ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.oonumerics.org/blitz/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Blitz++ 是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具像C++ 一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出的数值程序，比 Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利用C++的template技术，程序执行甚至可以比Fortran更快。 Blitz++目前仍在发展中，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以很容易地利用Blitz++所提供的函数来构建。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">POOMA </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.codesourcery.com/pooma/pooma </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在工业和研究环境中使用。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">MTL </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.osl.iu.edu/research/mtl/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如Intel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">CGAL <br /><br />　参考网站：www.cgal.org </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Computational Geometry Algorithms Library的目的是把在计算几何方面的大部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">游戏开发 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Audio/Video 3D C++ Programming Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.galacticasoftware.com/products/av/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">AV3D是一个跨平台，高性能的C++库。主要的特性是提供3D图形，声效支持（SB,以及S3M），控制接口（键盘，鼠标和遥感），XMS。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">KlayGE </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://home.g365.net/enginedev/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平台的游戏引擎，并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏先生为中国游戏开发事业所做出的贡献。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">OGRE </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.ogre3d.org </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">OGRE （面向对象的图形渲染引擎）是用C++开发的，使用灵活的面向对象3D引擎。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。引擎中的类库对更底层的系统库（如：Direct3D和OpenGL）的全部使用细节进行了抽象，并提供了基于现实世界对象的接口和其它类。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">线程 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">C++ Threads </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://threads.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个库的目标是给程序员提供易于使用的类，这些类被继承以提供在Linux环境中很难看到的大量的线程方面的功能。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">ZThreads </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://zthread.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">一个先进的面向对象，跨平台的C++线程和同步库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">序列化 <br />　s11n <br />　参考网站：http://s11n.net/ <br />　一个基于STL的C++库，用于序列化POD，STL容器以及用户定义的类型。 <br />　Simple XML Persistence Library <br />　参考网站：http://sxp.sourceforge.net/ <br />　这是个把对象序列化为XML的轻量级的C++库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">字符串 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">C++ Str Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.utilitycode.com/str/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">操作字符串和字符的库，支持Windows和支持gcc的多种平台。提供高度优化的代码，并且支持多线程环境和Unicode，同时还有正则表达式的支持。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Common Text Transformation Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://cttl.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较，插入，替换以及用EBNF的语法进行解析。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">GRETA </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://research.microsoft.com/projects/greta/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况下有非常优秀的表现。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">综合 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">P::Classes </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://pclasses.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot机制，i/o系统包括基于插件的网络协议透明的i/o架构，基于插件的应用程序消息日志框架，访问sql数据库的类等等。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">ACDK - Artefaktur Component Development Kit </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://acdk.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这是一个平台无关的C++组件框架，类似于Java或者.NET中的框架（反射机制，线程，Unicode，废料收集，I/O，网络，实用工具，XML，等等），以及对Java, Perl, Python, TCL, Lisp, COM 和 CORBA的集成。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">dlib C++ library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.cis.ohio-state.edu/~kingd/dlib/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">各种各样的类的一个综合。大整数，Socket，线程，GUI，容器类,以及浏览目录的API等等。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Chilkat C++ Libraries </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.chilkatsoft.com/cpp_libraries.asp </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这是提供zip，e-mail，编码，S/MIME，XML等方面的库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">C++ Portable Types Library (PTypes) </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.melikyan.com/ptypes/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这是STL的比较简单的替代品，以及可移植的多线程和网络库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">LFC </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://lfc.sourceforge.net/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">哦，这又是一个尝试提供一切的C++库 </p>
		<p style="font-size: 10pt; font-family: Arial;"> </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">其他库 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Loki </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.moderncppdesign.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">哦，你可能抱怨我早该和Boost一起介绍它，一个实验性质的库。作者在loki中把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过库来提供。同时还提供了智能指针这样比较实用的功能。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">ATL </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">ATL(Active Template Library)是一组小巧、高效、灵活的类，这些类为创建可互操作的COM组件提供了基本的设施。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">FC++: The Functional C++ Library </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">这个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表作。如果想要在OOP之外寻找另一分的乐趣，可以去看看函数式程序设计的世界。大师 Peter Norvig在 "Teach Yourself Programming in Ten Years"一文中就将函数式语言列为至少应当学习的6类编程语言之一。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">FACT! </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">参考网站：http://www.kfa-juelich.de/zam/FACT/start/index.html </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">另外一个实现函数式语言特性的库 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Crypto++ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">提供处理密码，消息验证，单向hash，公匙加密系统等功能的免费库。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">还有很多非常激动人心或者是极其实用的C++库，限于我们的水平以及文章的篇幅不能包括进来。在对于这些已经包含近来的库的介绍中，由于并不是每一个我们都使用过，所以难免有偏颇之处，请读者见谅。 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">资源网站 </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">正如我们可以通过计算机历史上的重要人物了解计算机史的发展，C++相关人物的网站也可以使我们得到最有价值的参考与借鉴，下面的人物我们认为没有介绍的必要，只因下面的人物在C++领域的地位众所周知，我们只将相关的资源进行罗列以供读者学习，他们有的工作于贝尔实验室，有的工作于知名编译器厂商，有的在不断推进语言的标准化，有的为读者撰写了多部千古奇作...... </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Bjarne Stroustrup http://www.research.att.com/~bs/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Stanley B. Lippman </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">http: //blogs.msdn.com/slippman/ 中文版 http: //www.zengyihome.net/slippman/index.htm<br />　Scott Meyers http://www.aristeia.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">David Musser http://www.cs.rpi.edu/~musser/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Bruce Eckel http://www.bruceeckel.com </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Nicolai M. Josuttis http://www.josuttis.com/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Herb Sutter http://www.gotw.ca/ </p>
		<p class="content" style="font-size: 10pt; font-family: Arial;">Andrei Alexandrescu http://www.moderncppdesign.com/</p>
		<p style="font-size: 10pt; font-family: Arial;">
				<br /> </p>
<img src ="http://www.cppblog.com/erran/aggbug/34119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 16:42 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：ACE和TAO 我的理解与感悟</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34116.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 08:34:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34116.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34116.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34116.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34116.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34116.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;">原文：<a href="http://dev.csdn.net/article/45/45577.shtm">http://dev.csdn.net/article/45/45577.shtm<br /></a>作者：<br /></p>
ACE和TAO 我的理解与感悟<br /> 
<p style="font-size: 10pt; font-family: Arial;">TAO和其他CORBA的基本都是按照OMG的提供的规范2.6来实现。在OMG的标准规范事实已经给出的CORBA的基础原型，基础数据定义，IDL语言语法，以及C++的代码映射等。我们可以在实现代码中经常看到规范的熟悉的方法函数和数据结构定义(可能是底层次和高层次的)，例如OMG的CORBA规范的orb，poa这两个重要的规范部分，基本上给出orb核，POA对象适配实现原型框架。要理解一个CORBA整个体系，就必须对CORBA的规范有一个总体的认识，这对实现的CORBA代码理解有极大的帮助，它起到对CORBA实现一个框架认识作用，对理解和看懂代码的实现会提到更高的层次。CORBA的规范可以说是它的骨架，实现则是给它造血和肉。</p><p style="font-size: 10pt; font-family: Arial;"> </p><p style="font-size: 10pt; font-family: Arial;">TAO是在ACE的基础上建立和开发出来的，在其中很多体现了ACE的思想和它的延伸。所以在ACE的熟悉程度上对TAO的理解的好比一个平台作用。实质上ACE的是通讯库，同时也是写通讯程序半成品库，ACE是TAO强有力的平台。事实上正是ACE的通讯库使得TAO的代码容易理解和划分，ACE更多体现在通讯的细节精细的实现和控制封装，在上层的使用上屏蔽容易错误的代码，把硬件平台和实现细节封装在底层代码中(ACE的OS.h代码占了ACE将10％的代码量);所以TAO的更多的是在围绕着CORBA的规范这种远过程调用实现逻辑上面；这样TAO的CORBA代码与ACE通讯库的划分非常清晰，通讯与CORBA实现逻辑一定程度的耦合被弱化，使得TAO的代码比其他的CORBA实现代码要容易理解和掌握。当初看TAO的代码感觉比较头痛，那是对ACE认识不够深，虽然接触的时间也很久，但停留在一个概念和初级应用的层次上，对ACE的库代码并没有在质的基础上深刻体会。随着自己看其他中间的的源代码和动手写自己的通讯库(很多概念来自ACE和另外一个CORBA的实现orbcus)和简单的远过程调用实现，从中遇到的问题和要解决的问题，要考虑的问题，要实现的问题等到深入到更本质的思考，发现最后的回到了CORBA要解决的问题上，自己在做别人已经做过，而且并见得做了更好得事情，实际上CORBA已经提出和解决及实现工业级方法。看了不实际做一些这些从新”发明轮子”的事情，对CORBA一些本质上的理解还真是很懵懂的，做一个自己得”轮子”还是很有帮助的，起码会对一些问题有更深的体会。这也对理解TAO的实现有作用。他们都是远过程调用的实现，简单概念复杂的实现，但基本共同的东西是相似的，但在实现上TAO却有强大和精妙之处，看着就觉的感撼，I can do it？。</p>
以前看orbcus只是源于使用jtc的线程库，后来有时间将orbcus的其他的代码的看了一些，特别是对CORBA CDR流化实现很有兴趣和SOCKET通讯代码，后来看来看去看1/3就晕了，就没精力看；通过个项目自己写了个通讯库用于简单的远过程调用就有更大的体会，就感觉自己写的这么幼稚和别人写的感觉没有一句废话，一次看orbcus的代码注释发现作者提到Apache的代码实现如何如何，说明作者就研究构Apache的代码，人家就有这样的深度和经历。确实在看orbcus的代码和写了些这方面的代码，回来再看TAO代码反而感觉的看TAO的代码好看很多，有顿悟的感觉，以前觉得ACE和TAO的代码不好看，而看orbcus的代码比较干净整洁有一种清纯的感觉；现在完全改观，看TAOACE感觉是顺畅的，这可能对ACE和TAO有更进一步的习惯认识和体会，遇到和解决问题更有感觉和目的性，而不是遇到问题对着代码就发蒙。ACETAO他们代码的注释量是非常大，而且有很多D.C的技术论文论述TAO CORBA实现技术细节和应用的模式理论，它的实现是专业级的，想到了你没有想到的问题解决你没解决的问题，如果自己从头写一个这样的东西简直是要命。运用和学习，再看他们实现的代码，每个星期坚持看一些类实现，好像真能感觉与一个世界级的专家们一起，感受他们的奉献和NB精神，更是令人敬畏的专业水准。 <br /><img src ="http://www.cppblog.com/erran/aggbug/34116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 16:34 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：Little Endian &amp; Big Endian</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34115.html</link><dc:creator>erran</dc:creator><author>erran</author><pubDate>Sat, 13 Oct 2007 08:23:00 GMT</pubDate><guid>http://www.cppblog.com/erran/archive/2007/10/13/34115.html</guid><wfw:comment>http://www.cppblog.com/erran/comments/34115.html</wfw:comment><comments>http://www.cppblog.com/erran/archive/2007/10/13/34115.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/erran/comments/commentRss/34115.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/erran/services/trackbacks/34115.html</trackback:ping><description><![CDATA[
		<p style="font-size: 10pt; font-family: Arial;" align="left">原文：<a href="http://dev.csdn.net/article/39/39864.shtm">http://dev.csdn.net/article/39/39864.shtm</a><br /><br /><strong> <span id="ArticleTitle1_ArticleTitle1_lblTitle">Little Endian &amp; Big Endian</span></strong>    <br /><br /><span id="ArticleContent1_ArticleContent1_lblContent">这个标题中的Endian是什么意思呢？还是让我们先来看看下面的情况，这是内存中一个WORD值中的内容，那么这个WORD中的值是0x1234呢，还是0x3412 ?  <br /><br />low byte high byte  <br />0x12      0x34  <br /><br />熟悉x86汇编的人立刻就知道这个值应为0x3412，很对，但在一些情况下，比如说你在SGI的机器上看到这种情况，则正好相反，0x1234才是正确答案，这与CPU内部处理数据的方式有关。这两种处理方式都存在于不同厂商生产的CPU之中，在上例中若此WORD值为0x3412的，我们称之为little-endian, 若为0x1234的，我们称之为big-endian，这是两种不同的byte orders。MSDN中有比较精确的定义如下： <br /><br />Byte Ordering Byte ordering Meaning  <br />big-endian The most significant byte is on the left end of a word.  <br />little-endian The most significant byte is on the right end of a word.  <br /><br />一般来说我们不用关心byte ordering的问题，但若要涉及跨平台之间的通信和资源共享，则不得不考虑这个问题了。也许你会说，我永远不会去用其它非x86的CPU，也许是这样，你甚至可以不必知道我们最常用的Intel，AMD等生产的x86的byte ordering是little-endian的，而且按现在的装机数量来看，可以说世界上绝大多数CPU是little-endian的，但多了解一些没有什么坏处，也许有用上的一天，实际若您要涉及到网络编程，了解一些还是有所帮助的，看完本文后您就应该知道为何socket编程中为何要用到如 ntohl, htonl, ntohs, htons这几个看起来名字似乎怪怪的API了，也很容易理解这些函数名的意义了。 <br /><br />假设我们要在不同byte ordering的机器之间传输和交换数据，那该怎么办呢，有两个方法，一是全部转换成文本来传输(如XML使用的)，另一个方法两方都按照某一方的byte order，这时就涉及到了不同byte order之间相互转换的问题（网络传输标准如TCP/IP采用第二种方法并且由于历史的原因，byte ordering是big-endian的）。两种之间该如何转换呢？方法有很多，我们可以先看看MFC中在处理serialize的代码中所用的方法(List), 虽然代码应该是高效易读的, 但我个人并不喜欢它, 原因是我觉得这不是一种通用优美的方法.下面列出的是我自己写的转换的代码： <br /><br />template <br />F3D_INLINE T ConvertEndian(T  t) <br />{ <br />   T tResult = 0; <br />   for (int  I = 0; I &lt; sizeof(T); ++ I) <br />   { <br />      tResult &lt;&lt;= 8;    <br />      tResult |= (t &amp; 0xFF) ; <br /><br />      t &gt;&gt;= 8; <br />   } <br />   return  tResult; <br />} <br /><br />原理非常简单，交换字节顺序，我就不多说了，当然这个写法并不是快速的, 只是通用的(我没条件试, 若有不对之处请指出), 若要快速的代码，可以在不同platform上用与platform相关的代码, 如在PowerPC上有 "load word byte-reversed indexed" (lwbrx) 和 "load halfword byte-reversed indexed" (lhbrx) 指令, 在x86上还可用BSWAP单个汇编指令等，在类型上专为int16, int32写的通用的代码也可以比这快得多.  <br /><br />当然如果在byte ordering相同的情况下，应该不必用这个转换函数，所以我们可以定义一个宏来处理不同的byte ordering，也可以在运行时测试byte ordering, 下面的代码给出了一个简单的测试方法。  <br /><br /><br />// Test for endianness. <br />F3D_INLINE bool IsLittleEndian(void) <br />{ <br />   DWORD dwTestValue = 0x12345678L; <br />   return  (*((BYTE*)&amp;dwTestValue) == 0x78); <br />} <br /><br />但是float比较怪，有可能所涉及到不仅仅是byte order的问题，因为有些平台如Alpha不使用IEEE的浮点格式，还得自己转换。当然同上，其它的方法一是将所用的float用文本方式输入输出，另一个办法是在某些情况下可将其转换成定点数再处理，这里我不再深入。 <br /><br />如果是读写第三方已经指定byte order的文件或数据流，比如说读SGI的位图文件格式，则可以直接自行按指定的byte order拼起来，不必考虑host机是何种byte ordering。下面我给出相应的代码： <br /><br /><br />// Read a little-endian TYPE from address <br />template <br />F3D_INLINE T GetLittleEndian(const BYTE*  pBuf) <br />{ <br />   T tResult = 0; <br />   pBuf += sizeof(T) - 1; <br />   for (int  I = 0; I &lt; sizeof(T); ++ I) <br />   { <br />      tResult &lt;&lt;= 8; <br />      tResult |= *pBuf --; <br />   } <br /><br />   return  tResult; <br />} <br /><br />// Read a big-endian TYPE from address <br />template <br />F3D_INLINE T GetBigEndian(const BYTE*  pBuf) <br />{ <br />   T tResult = 0; <br />   for (int  I = 0; I &lt; sizeof(T); ++ I) <br />   { <br />      tResult &lt;&lt;= 8; <br />      tResult |= *pBuf ++; <br />   } <br /><br />   return  tResult; <br />} <br /><br />// Set a little-endian TYPE on a address <br />template <br />F3D_INLINE void SetLittleEndian(BYTE*  pBuf, T  t) <br />{ <br />   for (int  I = 0; I &lt; sizeof(T); ++ I) <br />   { <br />   *pBuf ++ = BYTE(t &amp; 0xFF); <br />   t &gt;&gt;= 8; <br />   } <br />} <br /><br />// Set a big-endian T on a address <br />template <br />F3D_INLINE void SetBigEndian(BYTE*  pBuf, T  t) <br />{ <br />   pBuf += sizeof(T) - 1; <br />   for (int  I = 0; I &lt; sizeof(T); ++ I) <br />   { <br />      *pBuf -- = BYTE(t &amp; 0xFF); <br />      t &gt;&gt;= 8; <br />   } <br />} <br /><br />从上文可以看出，byte order挺简单的，一般应用中可能也用不上，但若您对写跨平台的程序有兴趣，则一定要了解的比较清楚才行。以上代码都是从实际使用的源码中取下来的。  <br /><br />附：常见Processor, OS的byte ordering情况 <br /><br />Processor OS Order  <br />x86 (Intel, AMD, … ) All little-endian  <br />DEC Alpha All little-endian  <br />HP-PA NT little-endian  <br />HP-PA UNIX big-endian  <br />SUN SPARC All? big-endian  <br />MIPS NT little-endian  <br />MIPS UNIX big-endian  <br />PowerPC NT little-endian  <br />PowerPC non-NT big-endian  <br />RS/6000 UNIX big-endian  <br />Motorola m68k All big-endian </span></p>
<img src ="http://www.cppblog.com/erran/aggbug/34115.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/erran/" target="_blank">erran</a> 2007-10-13 16:23 <a href="http://www.cppblog.com/erran/archive/2007/10/13/34115.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>电力产品公司网址录</title><link>http://www.cppblog.com/erran/archive/2007/10/13/34111.html</link><dc:creator>erran</dc:creator><author>erran</autho