??xml version="1.0" encoding="utf-8" standalone="yes"?>久久综合狠狠色综合伊人,青草国产精品久久久久久,亚洲国产日韩欧美综合久久http://www.shnenglu.com/zjj2816/category/2048.htmlzh-cnWed, 21 May 2008 21:26:59 GMTWed, 21 May 2008 21:26:59 GMT60xt umlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36991.html井泉井泉Tue, 20 Nov 2007 01:49:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36991.htmlhttp://www.shnenglu.com/zjj2816/comments/36991.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36991.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36991.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36991.htmlhttp://blog.csdn.net/zhangjunhd/   1Q关联(AssociationQ类之间的关联大多用来表C变量实例持有着对其他对象的引用?nbsp;  Phone拥有一个对Button的引用?nbsp;  2Q聚合(AggregationQ聚合是兌的一U特DŞ式,它意味着一U整?部分Qwhole/partQ的关系?nbsp;  一个整体不能是它自q一部分?因此 Q实例不能Ş成聚合回路,一个单独的对象不能够成为它自己的聚合,两个对象不能互相聚合Q三个对象不能Ş成一个聚合环。下图ؓ实例间的非法聚合循环Q?3Q组合(CompositionQ组合是一U特D的聚合形式?nbsp; UML对组合的定义Q?①如同聚合,实例不能有@环?②一个被所有者实例不能同时有两个所有者?③所有者负责被l合的对象的生命周期的管理。如果所有者被销毁,被所有者也必须跟着一赯销毁,如果所有者被复制Q被所有者也必须跟着一赯复制?br>

http://blog.csdn.net/dylgsy/archive/2006/08/16/1076044.aspx   UMLcd关系全面剖析

http://www.ibm.com/developerworks/cn/rational/r-shenzj/         利用Rational Roseq行C++代码和数据库l构分析



vs2008 支持 c++ cd?br>


井泉 2007-11-20 09:49 发表评论
]]>
使用和生成库http://www.shnenglu.com/zjj2816/archive/2006/07/24/10403.html井泉井泉Mon, 24 Jul 2006 07:04:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/07/24/10403.htmlhttp://www.shnenglu.com/zjj2816/comments/10403.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/07/24/10403.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/10403.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/10403.html
库有动态与静态两U,动态通常?so为后~Q静态用.a为后~。例如:libhello.so libhello.a

Z在同一pȝ中用不同版本的库,可以在库文g名后加上版本号ؓ后缀,例如Q?libhello.so.1.0,׃E序q接默认?so为文件后~名。所以ؓ了用这些库Q通常使用建立W号q接的方式?
ln -s libhello.so.1.0 libhello.so.1
ln -s libhello.so.1 libhello.so

使用?

当要使用静态的E序库时Q连接器会找出程序所需的函敎ͼ然后它们拷贝到执行文gQ由于这U拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言Q就不是q样。动态库会在执行E序内留下一个标记‘指明当E序执行Ӟ首先必须载入q个库。由于动态库节省I间Qlinux下进行连接的~省操作是首先连接动态库Q也是_如果同时存在静态和动态库Q不特别指定的话Q将与动态库相连接?
现在假设有一个叫hello的程序开发包Q它提供一个静态库libhello.a 一个动态库libhello.so,一个头文ghello.h,头文件中提供sayhello()q个函数
/* hello.h */
void sayhello();
另外q有一些说明文档。这一个典型的E序开发包l构
1.与动态库q接
linux默认的就是与动态库q接Q下面这D늨序testlib.c使用hello库中的sayhello()函数

/*testlib.c*/
#include <hello.h>
#include <stdio.h>

int main()
{
sayhello();
return 0;
}

使用如下命oq行~译
$gcc -c testlib.c -o testlib.o
用如下命令连接:
$gcc testlib.o -lhello -o testlib
在连接时要注意,假设libhello.o 和libhello.a都在~省的库搜烦路径?usr/lib下,如果在其它位|要加上-L参数
与与静态库q接ȝ一些,主要是参数问题。还是上面的例子Q?
$gcc testlib.o -o testlib -WI,-Bstatic -lhello
注:q个特别?-WIQ?Bstatic"参数Q实际上是传l了q接器ld.
指示它与静态库q接Q如果系l中只有静态库当然׃需要这个参C?
如果要和多个库相q接Q而每个库的连接方式不一P比如上面的程序既要和libhelloq行静态连接,又要和libbyeq行动态连接,其命令应为:
$gcc testlib.o -o testlib -WI,-Bstatic -lhello -WI,-Bdynamic -lbye
3.动态库的\径问?
Z让执行程序顺利找到动态库Q有三种ҎQ?
(1)把库拯?usr/lib?lib目录下?
(2)在LD_LIBRARY_PATH环境变量中加上库所在\径。例如动态库libhello.so?home/ting/lib目录下,以bashZQ用命令:
$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ting/lib
(3) 修改/etc/ld.so.conf文gQ把库所在的路径加到文g末尾Qƈ执行ldconfigh。这P加入的目录下的所有库文g都可见?
4.查看库中的符?
有时候可能需要查看一个库中到底有哪些函数Qnm命o可以打印出库中的涉及到的所有符受库既可以是静态的也可以是动态的。nm列出的符h很多Q常见的有三U,一U是在库中被调用Q但q没有在库中定义(表明需要其他库支持)Q用U表示Q一U是库中定义的函敎ͼ用T表示Q这是最常见的;另外一U是所谓的“弱态”符P它们虽然在库中被定义Q但是可能被其他库中的同名符可盖,用W表示。例如,假设开发者希望知道上央提到的hello库中是否定义了printf():
$nm libhello.so |grep printf
U printf
U表示W号printf被引用,但是q没有在函数内定义,由此可以推断Q要正常使用hello库,必须有其它库支持Q再使用ldd命o查看hello依赖于哪些库Q?
$ldd hello
libc.so.6=>/lib/libc.so.6(0x400la000)
/lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)
从上面的l果可以l箋查看printf最l在哪里被定义,有兴可以go on


生成?

W一步要把源代码~绎成目标代码。以下面的代码ؓ例,生成上面用到的hello库:
/* hello.c */
#include <stdio.h>
void sayhello()
{
printf("hello,world\n");
}
用gcc~绎该文Ӟ在编l时可以使用M全法的编l参敎ͼ例如-g加入调试代码{:
gcc -c hello.c -o hello.o

1.q接成静态库
q接成静态库使用ar命oQ其实ar是archive的意?
$ar cqs libhello.a hello.o
2.q接成动态库
生成动态库用gcc来完成,׃可能存在多个版本Q因此通常指定版本P
$gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o
另外再徏立两个符可接:
$ln -s libhello.so.1.0 libhello.so.1
$ln -s libhello.so.1 libhello.so
q样一个libhello的动态连接库q成了。最重要的是传gcc -shared 参数使其生成是动态库而不是普通执行程序?
-Wl 表示后面的参C是-soname,libhello.so.1直接传给q接器ldq行处理。实际上Q每一个库都有一个sonameQ当q接器发现它正在查找的程序库中有q样一个名Uͼq接器便会将soname嵌入q结中的二进制文件内Q而不是它正在q行的实际文件名Q在E序执行期间Q程序会查找拥有soname名字的文Ӟ而不是库的文件名Q换句话_soname是库的区分标志?
q样做的目的主要是允许系l中多个版本的库文g共存Q习惯上在命名库文g的时候通常与soname相同
libxxxx.so.major.minor
其中Qxxxx是库的名字,major是主版本Pminor 是次版本?img src ="http://www.shnenglu.com/zjj2816/aggbug/10403.html" width = "1" height = "1" />

井泉 2006-07-24 15:04 发表评论
]]>
新时代的门前 32位世界中?4位编E?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/07/07/9539.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 07 Jul 2006 05:51:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/07/07/9539.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/9539.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/07/07/9539.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/9539.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/9539.html</trackback:ping><description><![CDATA[ <strong>?6?2?4位架构编写可UL代码</strong> <br /> <br />  ?6位相比,32位意味着E序更快、可直接d讉K更多的内存和更好的处理器架构。鉴于此Q越来越多的E序员已l开始考虑利用64位处理器所带来的巨大优势了?br /><br />  克雷研究(Cray Research 应ؓ品牌?计算机已l开始?4位字Qƈ可访问更大的内存地址。然而,作ؓ正在向开发标准Y件和与其他操作系l相互努力的一部分Q我们已l停止了UL那些原本Z32位处理器的代码。事实上Q我们不断遇到我们称之ؓ?2位主义”的代码Q这些代码都是在假定机器字长?2位的情况下编写的Q因而很隄植这U代码,所以必ȝ立一些简单的指导斚wQ以便助于编写跨16?2?4位处理器q_的代码?br /><br />  ׃有一些遗留问题,<a class="bluekey" target="_blank">C?/a>a在数据类型和数据构造方面,昑־有点q剩了。可以用的不仅仅是char、short、int和longcdQ还有相应的unsignedQ无W号Q类型,当然你可在结?structure)和联?union)中؜合用,可以在联合中包含l构Q再在结构中包含联合Q如果还嫌数据类型不够复杂,q可以{换成比特位,当然也可以把一U数?a class="bluekey" target="_blank">cd转换</a>成另一U你惌的数据类型。正是因些工具太强大Q如果不安全C用它们,有可能会伤到自׃?br /><br />  <b>高代码的高U结?/b><br /><br />  在Kernighan和Plaugerl典的《The Elements of Programming Style》一书中Q他们的是“选择使程序看上去单的数据表示法”。对个h而言Q这意味着为高U编E用高U?a class="bluekey" target="_blank">数据l构</a>Q而低U编E用低U数据结构?br /><br />  在我们移植的E序中,有一个常见的32位主义bugQ不如拿它来做个例子Q科内尔大学~写的用于网间互访的路由协议引擎Q在伯克利网l环境下Q指TCP/IPQ,自然是用inet_addr( )来把表示Internet地址?a class="bluekey" target="_blank">字符?/a>转换成二q制形式。Internet地址y也是32位的Q就如运行伯克利|络pȝ的其他计机一P都是有着同样的字宽?<br /><br />  但也存在着有关Internet地址的高U定义:in_ addrl构。这个结构定义包括了子域s_ addrQ它是一个包含了Internet地址的unsigned long标量。inet_addr()接受一个指向字W的指针Qƈ且返回一个unsigned longQ在转换地址字符串过E中如果发生错误Qinet_addr返?1?br /><br />  E序Gatedd以文本格式存放Internet地址的配|文Ӟq把它们攑օsockaddr_inQ这是一个包含了l构in_addr的高U结构)。例1(a)中的代码可以?2位电脑上正常q行Q但UL到克LI计机上,却无法运行,Z么呢Q?br /><br />  ?Q高U代码的高l构<br /><br />  (a)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>struct sockaddr_in saddrin<br />char *str;<br /><br />if ((saddrin.sin_addr.s_addr = inet_addr(str)) == (unsigned long)-1) {<br /> do_some_error_handling;<br />}</td></tr></tbody></table><br />  (b)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>struct sockaddr_in saddrin<br />char *str;<br /><br />if (inet_aton(str, &saddrin.sin_addr) ! = OK) {<br /> do_some_error_handling;<br />}</td></tr></tbody></table><br />  因ؓ只要inet_addr能够正确地解析字W串Q那么一切OK。当inet_addr?4位计机上返回一个错误时Q这D代码却未能捕捉到。你必须要考虑比较语句中的数据位宽Q来定到底是哪Z错?br /><br />  首先Qinet_addrq回错误值——unsigned long -1Q在64位中表示为比特位全ؓ1Q这个D存储在结构in_addr下的子域s_addr中,而in_addr必须?2位来匚wInternet地址Q所以它是一?2比特位的unsigned intQ在我们的编译器上,int?4位)。现在我们存储进32?Q存储进的值将与unsigned long -1比较。当我们存储32?于unsigned intӞ~译器自动把32位提升ؓ64位;q样Q数?x00000000 ffffffff?xffffffff ffffffff的比较当然就p|了。这是一个很隑֏现的bugQ特别是在这U因?2位到64位的隐式提升上?br /><br />  那我们对q个bug怎么办呢Q一个解x法是在语句中比较0xffffffffQ而不?1Q但q又会代码更加依赖于特定大的对象。另一个方法是Q用一个中间的unsigned long变量Q从而在把结果存入sockaddr_in前,执行比较Q但q会让程序代码更复杂?br /><br />  真正的问题所在是Q我们期望一个unsigned longg一?2位量Q如Internet地址Q相{。Internet地址必须?2位Ş式进行存储,但有些时候用一个标量,来访问这个地址的一部分Q是非常方便的。在32位字长的电脑中,用一个long数|常被当作32位)来访问这个地址Q看上去没什么问题。让我们暂时不想一个低U的数据(32位Internet地址Q是否与一个机器字相等Q那么高U数据类型结构in_addr应该被一直用。因为in_addr中没有无效|那么应有一个单独的状态用作返回倹{?br /><br />  解决Ҏ是定义一个新的函敎ͼ像inet_addr那样Q但q回一个状态|而且接受一个结构in_addr作ؓ参数Q参见例1(b)。因为高U的数据元素可以一直用,而返回的值是没有溢出的,所以这个代码是可以跨架构移植的Q而不字长是多少。虽然伯克利发布了NET2Q其中的定义了一个新的函数inet_aton()Q但如果试着改变inet_addr()中的代码Q将会损坏许多程序?br /><br />  <b>低代码的低U结?/b><br /><br />  低~程意味着直接操纵物理讑֤或者特定协议的通讯格式Q例如,讑֤驱动E序l常使用非常_的位模式来操U|制寄存器。此外,<a class="bluekey" target="_blank">|络协议</a>通过特定的比特位模式传输数据ҎQ也必须适当地{译?br /><br />  Z操纵物理数据,此处的数据结构必d地反映被操U늚内容。比特位是一个不错的选择Q因为它们正好指定了比特的位数及排列。事实上Q正是这U精度Q比特位相对于short、int、longQ更好地映像了物理结构(short、int、long会因为电脑的不同而改变,而比特位不会Q?br /><br />  当映像一个物理结构时Q是通过定义格式来比特位达到这U精度的Q这׃你必M直用一U编码风格来讉Kl构。此时的每个位域都是命名的,你写出的代码可直接访问这些位域。当讉K物理l构Ӟ有g事可能你q不惛_做,那就是用标量数l?short、int、or long)Q访问这些数l的代码都假定存在一个特定的比特位宽Q当ULq些代码CC用不同字宽的电脑上时Q就可能不正了?br /><br />  在我们移植PEX囑փ库时遇到的一个问题,涉及到其映像的协议消息l构。在某台电脑上,如果int整型的长度与消息中的元素一P那例2(a)中的代码׃工作得很正常?2位的数据元素?2字长的电脑上没有问题Q拿?4位的克雷计算ZQ它出错了。对?(b)而言Q不单要改变l构定义Q还要改变所有涉及到coord数组的代码。这P摆在我们面前有两个选择Q要么重写涉及此消息的所有代码,要么定义一个低U的l构和一个高U的l构Q然后用一D늉D的代码把数据从一个拷贝到另一个当中,不过我也不期望可以找出每个对zcoord = draw_ msg.coord[2]的引用,而且Q当现在需要移植到一个新架构上时Q把所有的代码都改写成如例2(c)所C无疑是一艰苦的工作。这个特D的问题是由于忽视字长的不同而带来的Q所以不能假讑֜可移植的代码中机器字ѝshort、int、long都是h同样的大?br /><br />  ?Q低U代码的低l构<br /><br />  (a)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>struct draw_msg {<br /> int objectid;<br /> int coord[3];<br />}</td></tr></tbody></table><br />  (b)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>struct draw_msg {<br /> int objectid:32;<br /> int coord1:32;<br /> int coord2:32;<br /> int coord3:32;<br />}</td></tr></tbody></table><br />  (c)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>int *iptr, *optr, *limit;<br />int xyz[3];<br /><br />iptr = draw_msg.coord;<br />limit = draw_msg.coord + sizeof(draw_msg.coord);<br /><br />optr = xyz;<br />while (iptr < limit)<br />*optr++ = *iptr++;</td></tr></tbody></table><strong>l构打包和字寚w<br /><br /></strong>   正是因ؓ~译器会对结构进行打包,所以不同计机上字长的变化Q还D了另一个问题。C~译器在?word)的边界上寚w字长Q当h一个字长的数据后面紧接着一个较的数据Ӟq种Ҏ会生内存空~(不过也有例外Q比如说当有_多的数据刚好可以填充一个字Ӟ?br /><br />   一些聪明的E序员在声明联合Ӟ往往在其中会带有两个或更多的l构Q其中一个结构刚好填充联合,另一个则可以用来从不同的角度来看待这个联合,参见?(a)。假设这D代码是?6位字长的计算机所写,int?6位,long?2位,那么存取q个l构的代码将会得到正常的映射关系Q如?Q,而例3(b)中的代码也会按预期的那样工作。可是,如果q段代码一旦移植到另一台具?2位字长的计算ZӞ映射关系改变了。如果新计算Z的编译器允许你?6位的intQ那么字的对齐就会像?所CZQ或者如果编译器遵@K&RU定Q那么int会和一个字Q?2比特Q一样长Q对齐就如图3所C,在Q一情况下,q都导致问题?br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/s1w5hkl49xdt.GIF" border="0" /><br /><img src="http://dev.yesky.com/imagelist/05/11/50e62q83lvi5.GIF" border="0" /><br /><img src="http://dev.yesky.com/imagelist/05/11/zn99pw345649.GIF" border="0" /></div></td></tr></tbody></table><br />  ?Q结构打包和字对?br /><br />  (a)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>union parse_hdr {<br /> struct hdr {<br />  char data1;<br />  char data2;<br />  int data3;<br />  int data4;<br />} hdr;<br />struct tkn {<br /> int class;<br /> long tag;<br />} tkn;<br />} parse_item;</td></tr></tbody></table><br />  (b)<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>char *ptr = msgbuf;<br /><br />parse_item.hdr.data1 = *ptr++;<br />parse_item.hdr.data2 = *ptr++;<br />parse_item.hdr.data3 = (*ptr++ << 8 | *ptr++);<br />parse_item.hdr.data4 = (*ptr++ << 8 | *ptr++);<br /><br />if (parse.tkn.class >= MIN_TOKEN_CLASS && parse.tkn.class <= MAX_TOKEN_CLASS) {<br /> interpret_tag(parse.tkn.tag);<br />}</td></tr></tbody></table><br />  在第一个情况中Q图2Q,tag域不是像期望的那L性拉长,而被填充了一些垃圾。而在W二个情况中Q图3Q,无论是classq是tag域,都不再有意义Q两个char值因打包成一个intQ所以也都不再正。再ơ强调,首先不要假设标准数据cd大小一P其次q要了解它们是怎样被映成其他数据cd的,q才是书写可UL代码的最好方法?br /><br />  <b>机器dҎ?/b><br /><br />  几乎所有的处理器都在字边界上以字ؓ单位q行dQ而且通常都ؓ此作了一些优化。另有一些的处理器允许其他类型的dQ如以字节ؓ单位d、或在半个字边界上以半字为单位寻址Q甚臌有一些处理器有辅助硬件允许在奇数边界上同时以字和半字q行d?br /><br />  d机制在不同计机上会有所变化Q最快的d模式是在字边界上以字为单位进行寻址。其他方式的d需要辅助硬Ӟ通常都会对内存访问增加了一些时钟周期。而这些过多的模式和特D硬件的支持Q是与RISC处理器的设计初衷背道而驰的,拿克雷计算机来_只支持在字边界上以字ؓ单位q行d?br /><br />  在那些不提供多种数据cdd方式的计机上,~译器可以提供一些模拟。例如:~译器可以生成一些指令,当读取一个字Ӟ通过UM和屏蔽,来找到所惌的位|,以此来模拟在字中的半字寻址Q但q会需要额外的旉周期Qƈ且代码体U会更大?br /><br />  从这点上来说Q位域的效率是非怽的,在以位域来取Z个字Ӟ它们产生的代码体U最大。当你存取同一个字中的其他位域Ӟ又需要对包含q个位域字的内存Q重新进行一遍寻址Q这是典型的以I间换时间?<br /><br />  当在设计数据l构Ӟ我们L想用可以保存数据的最数据类型,来达到节省空间的目的。我们有时小气得l常使用char和shortQ来存取位特域,q就像是Z节省一角钱Q而花了一元钱。储存空间上的高效,会付出在E序速度和体U上隐藏的代仗?br /><br />  试想你只Z个紧凑结构分配了一点的空_但却产生了大量的代码来存取结构中的域Q而且q段代码q是l常执行的,那么Q会因ؓ非字dQ而导致代码运行缓慢,而且充斥了大量用于提取域的代码,E序体积也因此增大。这些额外代码所占的I间Q会让你前面省空间所做的努力付之东流?br /><br />  在高U数据结构中Q特定的比特定位已不是必ȝ了,应在所有的域中都用字(word)Q而不要操心它们所占用的空间。特别是在程序某些依赖于机器的部分,应该为字准备一个typedefQ如下:<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>/*在这台计机上,int是一个字?/<br />typedef word int;</td></tr></tbody></table><br />  在高U结构中Q对所有域都用字有如下好处:<br /><br />  a.. 对其他计机架构的可UL?<br /><br />  b.. ~译器可能生成最快的代码 <br /><br />  c.. 处理器可能最快地讉K到所需内存 <br /><br />  d.. l对没有l构寚w的意外发?br /><br />  必须也承认,在某些时候,是不能做到全部用字的。例如,有一个很大的l构Q但不会被经常存取,如果使用了数千个字的话,体积会增大25%Q但使用字通常会节省空间、提高执行速度Q而且更具UL性?br /><br />  <b>以下是我们的l论Q?/b><br /><br />  书写跨^台移植的代码Q其实是件简单的事情。最基本的规则是Q尽可能地隐藏机器字长的l节Q用非常_的数据元素位大小来映物理数据结构。或者像前面所的,为高U编E用高U数据结构,而低U编E用低U数据结构,当阐明高U数据结构时Q对标准C的标量类型,不要作Q何假?img src ="http://www.shnenglu.com/zjj2816/aggbug/9539.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-07-07 13:51 <a href="http://www.shnenglu.com/zjj2816/archive/2006/07/07/9539.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言~程---性能优化http://www.shnenglu.com/zjj2816/archive/2006/07/07/9535.html井泉井泉Fri, 07 Jul 2006 05:16:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/07/07/9535.htmlhttp://www.shnenglu.com/zjj2816/comments/9535.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/07/07/9535.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9535.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9535.html使用宏定?br />
  在C语言中,宏是产生内嵌代码的唯一Ҏ。对于嵌入式pȝ而言Qؓ了能辑ֈ性能要求Q宏是一U很好的代替函数的方法?br />
  写一?标准"宏MIN Q这个宏输入两个参数q返回较的一个:

  错误做法Q?br />
#define MIN(A,B)  ( A <= B ? A : B )

  正确做法Q?br />
#define MIN(A,B) Q(AQ?lt;= (B) ? (A) : (B) )

  对于宏,我们需要知道三点:

  (1)宏定??函数Q?br />
  (2)宏定义不是函敎ͼ因而需要括上所?参数"Q?br />
  (3)宏定义可能生副作用?br />
  下面的代码:

least = MIN(*p++, b);

  被替换为:

( (*p++) <= (b) ?(*p++):(b) )

  发生的事情无法预料?

  因而不要给宏定义传入有副作用的"参数"?br />
  使用寄存器变?/b>

  当对一个变量频J被dӞ需要反复访问内存,从而花费大量的存取旉。ؓ此,C语言提供了一U变量,卛_存器变量。这U变量存攑֜CPU的寄存器中,使用Ӟ不需要访问内存,而直接从寄存器中dQ从而提高效率。寄存器变量的说明符是register。对于@环次数较多的循环控制变量及@环体内反复用的变量均可定义为寄存器变量Q而@环计数是应用寄存器变量的最好候选者?br />
  (1) 只有局部自动变量和形参才可以定义ؓ寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量Q包括:模块间全局变量、模块内全局变量、局部static变量Q?br />
  (2) register是一?"型关键字Q意指程序徏议该变量攑֜寄存器中Q但最l该变量可能因ؓ条g不满_ƈ未成为寄存器变量Q而是被放在了存储器中Q但~译器中q不报错Q在C++语言中有另一?"型关键字QinlineQ?br />
  下面是一个采用寄存器变量的例子:

/* ?+2+3+?+n的?*/
WORD Addition(BYTE n)
{
 register i,s=0;
 for(i=1;i<=n;i++)
 {
  s=s+i;
 }
 return s;
}

  本程序@环nơ,i和s都被频繁使用Q因此可定义为寄存器变量?br />
  内嵌汇编

  E序中对旉要求苛刻的部分可以用内嵌汇编来重写,以带来速度上的显著提高。但是,开发和试汇编代码是一件辛苦的工作Q它花Ҏ长的旉Q因而要慎重选择要用汇编的部分?br />
  在程序中Q存在一?0-20原则Q即20%的程序消耗了80%的运行时_因而我们要改进效率Q最主要是考虑改进?0%的代码?br />
  嵌入式CE序中主要用在U汇~,卛_CE序中直接插入_asm{ }内嵌汇编语句Q?br />
/* 把两个输入参数的值相加,l果存放到另外一个全局变量?*/
int result;
void Add(long a, long *b)
{
 _asm
 {
  MOV AX, a
  MOV BX, b
  ADD AX, [BX]
  MOV result, AX
 }
}

  利用gҎ?/b>

  首先要明白CPU对各U存储器的访问速度Q基本上是:

CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM

  对于E序代码Q已l被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常q不是一个好办法Q我们最好在pȝ启动后将FLASH或ROM中的目标代码拯入RAM中后再执行以提高取指令速度Q?br />
  对于UART{设备,其内部有一定容量的接收BUFFERQ我们应量在BUFFER被占满后再向CPU提出中断。例如计机l端在向目标机通过RS-232传递数据时Q不宜设|UART只接收到一个BYTE向CPU提中断,从而无谓浪费中断处理时_

  如果Ҏ讑֤能采取DMA方式dQ就采用DMAdQDMAd方式在读取目标中包含的存储信息较大时效率较高Q其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式Q减了CPU 对外讄q预Q进一步提高了CPU与外讄q行操作E度?br />
  zȝ位操?/b>

  使用C语言的位操作可以减少除法和取模的q算。在计算机程序中数据的位是可以操作的最数据单位,理论上可以用"位运?来完成所有的q算和操作,因而,灉|的位操作可以有效地提高程序运行的效率。D例如下:

/* Ҏ1 */
int i,j;
i = 879 / 16;
j = 562 % 32;
/* Ҏ2 */
int i,j;
i = 879 >> 4;
j = 562 - (562 >> 5 << 5);

  对于?的指数次方ؓ"*"?/"?%"因子的数学运,转化为移位运?<< >>"通常可以提高法效率。因Z除运指令周期通常比移位运大?br />
  C语言位运除了可以提高运效率外Q在嵌入式系l的~程中,它的另一个最典型的应用,而且十分q泛地正在被使用着的是位间的与Q?amp;Q、或Q|Q、非Q~Q操作,q跟嵌入式系l的~程特点有很大关pR我们通常要对g寄存器进行位讄Q譬如,我们通过AM186ER?0186处理器的中断屏蔽控制寄存器的W低6位设|ؓ0Q开中断2Q,最通用的做法是Q?br />
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp &~INT_I2_MASK);

  而将该位讄?的做法是Q?br />
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp | INT_I2_MASK);

  判断该位是否?的做法是Q?br />
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{
?/* 该位? */
}

  上述Ҏ在嵌入式pȝ的编E中是非常常见的Q我们需要牢固掌握?

  ȝ

  在性能优化斚w永远注意80-20准备Q不要优化程序中开销不大的那80%Q这是劳而无功的?br />
  宏定义是C语言中实现类似函数功能而又不具函数调用和返回开销的较好方法,但宏在本质上不是函数Q因而要防止宏展开后出C可预料的l果Q对宏的定义和用要慎而处之。很遗憾Q标准C至今没有包括C++中inline函数的功能,inline函数兼具无调用开销和安全的优点?br />
  使用寄存器变量、内嵌汇~和zȝ位操作也是提高程序效率的有效Ҏ?br />
  除了~程上的技巧外Qؓ提高pȝ的运行效率,我们通常也需要最大可能地利用各种g讑֤自n的特Ҏ减小其运转开销Q例如减中断次数、利用DMA传输方式{?

井泉 2006-07-07 13:16 发表评论
]]>
c# ?chttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9025.html井泉井泉Mon, 26 Jun 2006 10:41:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9025.htmlhttp://www.shnenglu.com/zjj2816/comments/9025.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9025.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9025.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9025.html1.可以单的认ؓ 一?h 文g对应一?br />2.用static变量Q加全局函数 替代 全局变量Q模仿属性概c?br />3.宏的作用 实现默认参数Q常量,与?#”连接字W串操作W实现动态名U?br />4.强大的位操作
5.动态内存分?br />6.函数指针Q回调机Ӟ事g机制Q消息机?/p>

井泉 2006-06-26 18:41 发表评论
]]>
C语言中的面向对象http://www.shnenglu.com/zjj2816/archive/2006/06/26/9024.html井泉井泉Mon, 26 Jun 2006 10:31:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9024.htmlhttp://www.shnenglu.com/zjj2816/comments/9024.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/26/9024.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9024.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9024.html


一?面向对象思想的目的是框架化,手段是抽?br />
怿很多人都明白面向对象讲了什么:c,抽象c,l承Q多态。但是是什么原因促使这些概늚产生呢?

打个比方_你去买显C器Q然而显C器的品牌样式是多种多样的,你在买的q程中发生的事情也是不可预测的。对于这L事情Q我们在E序语言中如何去描述呢。面向对象的思想是Z解决q样的问题。编写一个程序(甚至说是一个工E)Q从无到用是困难的,从有C富是更加困难的。面向对象将E序的各个行为化为对象,而又用抽象的办法这些对象归c(抽象Q,从而将错综复杂的事情简化ؓ几个主要的有机组合(框架化)?br />
其实我们的n边很多东襉K是这L成的Q比如说电脑Q电脑是׃板,CPU加上各种卡组成的。这是一个框架化。而忽略不同的CPUQ不同的LQ不同的声卡Q网卡,昑֍的区别,q就是抽象。再比如说现在的教育|:是由L心节点:清华Q北大,北邮{几个,然后是各个子节点Q依ơ组成了整个教育|网l?br />
所以我觉得面向对象的编E思想是Q一个大型工E是分层ơ结构的Q每层又由抽象的l构q接为整体(框架化)Q各个抽象结构之间是彼此独立的,可以独立q化Q承,多态)。层ơ之_l构之间各有l一的通讯方式Q通常是消息,事g机制Q?br />
二?以前 C 语言~程中常用的“面向对象”方?br />
其实C语言诞生以来Qh们就想了很多办法来体现“面向对象”的思想。下面就来说说我所知道的方法。先说一些大家熟悉的东东Q慢慢再讲诡异的。呵?br />
1Q?宏定义:

有的Z要问,宏定义怎么扯到q里来了Q我们可以先看一个简单的例子Q?br />
Qdefine MacroFunction Afunction

然后在程序里面你调用了大量的AFunctionQ但是有一天,你突然发C要用BFunction了,Q不qAFunction又不能不要,很有可能你以后还要调用)Q这个时候,你就可以Qdefine MacroFunction Bfunction来达到这L目的?br />
当然Q不得不说这L办法是too simpleQsometime naïve的,因ؓ一个很滑稽的问题是如果我一般要改ؓBFunctionQ一半不变怎么办? 那就只好查找替换了?br />
2Q?静态的入口函数Q保证函数名相同Q利用标志位调用子函敎ͼ

q样的典型应用很多,比如说网卡驱动里面有一个入口函数NilanQint FunctionCodeQPara*Q。具体的参数是什么记不清楚了。不qNiLan的主体是q样的:

Long NilanQint FunctionCodeQPara*Q{

Switch(FunctionCode){

Case SendPacket: send(?)

Case ReceivePacket: receive(?

?.

}

写到q里大家明白什么意思了吧。保证相同的函数名就是说Q网卡驱动是和pNA+协议栈互q的Q那么如何保证pNA+协议栈和不同的驱动都兼容呢,一个简单的办法是仅仅使用一个入口函数。通过改变如果函数的参数|来调用内部的各个函数。这L做法是可以进化的Q如果以后想调用新的函数Q增加相应的函数参数值就好了。如果我们将|卡驱动和pNA+协议栈看作两个层的话Q我们可以发玎ͼ

层与层之间的互连接口是很的Q这里是一个入口函敎ͼQ一般是采用名字解析的办法而不是具体的函数调用Q利用FunctionCode调用函数QNilan仅仅实现名字解析的功能) ――!接口限制和名字解?br />
接口限制Q层与层之间仅仅知道有限的函?br />
名字解析Q层与层之间建立共同的名字与函数的对应关p,之间利用名字调用功能?br />
3QCALLBACK函数?br />
我觉得这是C语言的一个创举,虽然它很单,p如何把鸡蛋竖h一P但是你如果没惛_的话Q嘿ѝ如果说静态入口函数实C一个可理的宏观的话,CallBack是实现了一个可q化的微观:它得一个函数可以在不重新编译的情况下实现功能的dQ但是在最最早期的时候,也有蛮多人持反对态度Q因为它用了函数指针。函数指针虽然灵z,但是׃它要讉K内存两次才可以调用到函数Q第一ơ访问函数指针,W二ơ才是真正的函数调用。它的效率是不如普通函数的。但是在一个不太苛ȝ环境下,函数调用本n׃怎么耗时Q函数指针的性能又不是特别糟p,使用函数指针其实是一个最好的选择。但是函数指针除了性能Q最ȝ的地方就是会DE序的“支ȝ”。试惻I在程序中Q你d一个函数指针的时候,如果你愣是不知道q个函数指针指向的是哪个函数Q那个感觉真的很p糕。(可以看后面的文章Q要使用先进的程序框Ӟ避免q样的情况)

三?Event ?Message

看了上面的描qͼ怿大家多少有些明白Z么要使用Event和Message了。具体的函数调用会带来很多的问题Q虽然从效率上讲Q这样做是很好的Q。ؓ了提高程序的灉|性,Event和Message的办法生了。用名字解析的办法代曉K常的函数调用,q样Q如果双方对q样的解析是一致的话,可以达C个统一。不qEvent和Message的作用还不仅仅是如此?br />
Event和Messageq有建立q程间通信的功能。进E将自己的消息发l“控制中心”(单的是一个消息队列,和一个while循环不断的取消息队列的内容ƈ执行Q,控制E序得到消息Q分发给相应的进E,q样其他q程可以得到这个消息ƈq行响应?br />
Event和Message是很灉|的,因ؓ你可以随时添加或者关闭一个进E,Q仅仅需要添加分发消息的列表可以了QEvent和Message 从程序实C我觉得是一LQ只不过概念不同。Event多用于指一个动作,比如g发生了什么事情,需要调用一个什么函数等{。Message多用于指一个指C,比如什么程序发生了什么操作命令等{?br />
四?结

其实~程序和写文章一P都是先有一个提UԌ然后慢慢的丰富。先抽象化得到程序的骨架Q然后再考虑各个斚w的其他内容:E序极端的时候会发生什么问题?E序的这个地方的功能现在q不完善Q以后再完善会有什么问题?E序是不是可以扩展的Q?br />
二、类模拟的性能分析

  cL拟中使用了大量的函数指针Q结构体{等Q有必须Ҏq行性能分析Q以便观察这Ll构对程序的整体性能有什么程度的影响?br />
  1Q函数调用的开销

#define COUNTER XX
void testfunc()
{
  int i,k=0;
  for(i=0;i<YY;i++)
}

  在测试程序里面,我们使用的是一个测试函敎ͼ函数体内部可以通过改变YY的值来改变函数的耗时。测试对比是 循环调用XXơ函敎ͼ和@环XXơ函数内部的YY循环?br />
  l果发现Q在YY_,X_大的情况下,函数调用耗时成ؓ了主要原因。所以当一个“简单”功能需要“反复”调用的时候,它~写为函数将会对性能有媄响。这个时候可以用宏Q或者inline关键字?br />
  但是Q实际上我设|XXQ?0000000Q?千万Q的时候,才出现msU别的耗时Q对于非实时操作QUI{等Q,即是很慢的cpuQ嵌入式10MU别的)Q也只会在XXQ?0万的时候出现短暂的函数调用耗时Q所以实际上q个是可以忽略的?br />
  2Q普通函数调用和函数指针调用的开销

void (*tf)();
tf=testfunc;

  试E序修改Z个用函数调用,一个用函数指针调用。测试发现对旉基本没有什么媄响。(在第一ơ编写的时候,发现在函数调用出现耗时的情况下QXXQ?亿)Q函数指针的调用要慢Qrelease版本Q,调用耗时350Q?00。后来才发现q个影响是由于将变量甌为全局的原因,全局变量的访问要比局部变量慢很多Q?br />
  3Q函数指针和指针l构讉K的开销

struct a {
  void (*tf)();
}

  试E序修改Z用结构的函数指针Q测试发现对旉基本没有什么媄响。其实用结构ƈ不会产生影响Q因为结构的讉K是固定偏U量的。所以结构变量的讉K和普通变量的讉K对于机器码来说是一L?br />
  试l论Q用类模拟的办法对性能不会产生太大的媄响?br />
三、C语言的多态实?br />
  怿很多人都看过设计模式斚w的书Q大家有什么体会呢QBridgeQProxyQFactoryq些设计模式都是Z抽象cȝ。用抽象对象是q里的一个核心?br />   
  其实我觉得框架化~程的一个核心问题是抽象Q用抽象的对象构建程序的M框架Q这是面向对象编E的普遍思想。用抽象构徏骨架Q再加上多态就形成了一个完整的E序。由于CQ+语言本n实现了承和多态,使用q样的编E理念(理念啥意思?跟个风,嘿嘿Q在CQ+中是十分普遍的现象,可以说VirtualQ多态)是VC的灵?br />
  但是Q用C语言的我们都快把q个多态忘光光了。我常听见前辈说Q类Q多态?我们用的是CQ把q些忘了吧。很不幸的是Q我是一个固执的人。这么好的东西,为啥不用呢。很高兴的,在最q的一些纯C代码中,我看见了C中的多态!下面且听我慢慢道来?br />
  1. VC中的Interface是什?br />
  InterfaceQ中文解释是接口Q其实它表示的是一个纯虚类。不q我所要说的是Q在VC中的Interface其实是structQ查找Interface的定义,你可以发现有q样的宏定义Q?br />
    #Ifndef Interface
    #define Interface struct
    #endif

  而且Q实际上在VC中,如果一个类有Virtual的函敎ͼ则类里面会有vtableQ它实际上是一个虚函数列表。实际上CQ+是从C发展而来的,它不q是在语aU别上支持了很多新功能,在C语言中,我们也可以用这L功能Q前提是我们不得不自己实现?br />
  2QC中如何实现纯虚类Q我U它为纯虚结构)

  比较前面Q相信大家已l豁然开朗了。用structl合函数指针可以实现纯虚类?br />
  例子Q?br />
  typedef struct {
    void (*Foo1)();
    char (*Foo2)();
    char* (*Foo3)(char* st);
  }
  MyVirtualInterface;
   
  q样假设我们在主体框架中要用桥模式。(我们的主cLDoMyActQ接口具体实现类是Act1QAct2Q下面我依ơ介l这些“类”。(C中的“类”在前面有说明,q里换了一个,是用早期的数组的办法)

  ȝDoMyActQ?ȝ中含有MyVirtualInterface* m_pInterface; ȝ有下函数Q?br />
  DoMyAct_SetInterface(MyVirtualInterface* pInterface)
  {
    m_pInterface= pInterface;
  }
  DoMyAct_Do()
  {
    if(m_pInterface==NULL) return;
    m_pInterface->Foo1();
    c=m_pInterface->Foo2();
  }

  子类Act1Q实现虚l构Q含有MyVirtualInterface st[MAX]; 有以下函敎ͼ

  MyVirtualInterface* Act1_CreatInterface()
  {
    index=FindValid() //对象池或者用Malloc Q应该留在外面申P实例?br />    if(index==-1) return NULL;
    St[index].Foo1=Act1_Foo1; // Act1_Foo1要在下面具体实现
    St[index].Foo2=Act1_Foo2;
    St[index].Foo3=Act1_Foo3;
    Return &st [index];
  }

  子类Act2同上?br />
  在main中,假设有一个对象List。List中存贮的是MyVirtualInterface指针Q则有:

  if( (p= Act1_CreatInterface()) != NULL)
  List_AddObject(&List, p); //Add Al

  While(p=List_GetObject()){
    DoMyAct_SetInterface(p);//使用Interface代替了原来大幅的Switch Case
    DoMyAct_Do();//不要理会具体的什么样的动作,just do it
  }

  FREE ALL

四、类模拟和多?l承

  在面向对象的语言里面Q出Ccȝ概念。这是编E思想的一U进化。所谓类Q是对特定数据的特定操作的集合体。所以说cd含了两个范畴Q数据和操作。而C语言中的struct仅仅是数据的集合。(liyuming1978@163.com)

  1Q实例:下面先从一个小例子看v

#ifndef C_Class
    #define C_Class struct
#endif

C_Class A {
    C_Class A *A_this;
    void (*Foo)(C_Class A *A_this);
    int a;
    int b;
};

C_Class B{           //Bl承了A
    C_Class B *B_this; //序很重?br />    void (*Foo)(C_Class B *Bthis);         //虚函?br />    int a;
    int b;

    int c;
};


void B_F2(C_Class B *Bthis)
{
    printf("It is B_Fun\n");
}

void A_Foo(C_Class A *Athis)
{
    printf("It is A.a=%d\n",Athis->a);//或者这?br />//   exit(1);
//   printf("U虚 不允许执行\n");//或者这?br />}

void B_Foo(C_Class B *Bthis)
{
    printf("It is B.c=%d\n",Bthis->c);
}

void A_Creat(struct A* p)
{
    p->Foo=A_Foo;
    p->a=1;
    p->b=2;
    p->A_this=p;
}


void B_Creat(struct B* p)
{
    p->Foo=B_Foo;
    p->a=11;
    p->b=12;    
    p->c=13;
    p->B_this=p;
}


int main(int argc, char* argv[])
{
    C_Class A *ma,a;
    C_Class B *mb,b;

    A_Creat(&a);//实例?br />    B_Creat(&b);

    mb=&b;
    ma=&a;

    ma=(C_Class A*)mb;//引入多态指?br />    printf("%d\n",ma->a);//可惜的就?函数变量没有private
    ma->Foo(ma);//多?br />    a.Foo(&a);//不是多态了
    B_F2(&b);//成员函数Q因为效率问题不使用函数指针
    return 0;
}


  输出l果Q?br />
11
It is B.c=13
It is A.a=1
It is B_Fun</P< p>

井泉 2006-06-26 18:31 发表评论
]]>
޹Ʒľþþ| Ը߳þþþþþþþ| þøŮ߳MBA| һһþAþۺϾƷ| þþһƷ99þþƷ66| Ʒþþþ| ձǿƬþþþþAAA| þþþþ޾Ʒ| ҹƷþ2021| ٸþĻ | þСƵ| þþþþƷAV| þùѾƷ| պӰԺþ| Ʒŷһþþ| þþþAVվ| Ʒþþþþ| þþƷavպ| ĻƷþ| þۺձ츾| ĻþþƷ| һþ㽶߿ۿ| һֻƴƬ99þ| ޾ƷþþþþĻ| þþþþþþ˳| 99þҹҹƷ| þˬˬƬav鷳 | Ʒþþ21p| ݺɫۺϾþþþ| þùƷþþ| AVþþþò| þwwƷw˳| Ʒѿþþ| Ʒʾþþþ999Ұ| ˳˳ۺþþ| þۺϹɫ88þþƷۺ| һɫþ88ձȡۺ| Ʒþþþһ| ó˾þAvѸ| 99þùۺ| ݺɫþۺ|