﻿<?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++博客-牵牛散步-随笔分类-ICE学习资料</title><link>http://www.cppblog.com/klsmlzm/category/558.html</link><description>暂时无</description><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 08:36:45 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 08:36:45 GMT</pubDate><ttl>60</ttl><item><title>LINUX下简单的编译和使用动态链接库[compile .so use c++ in linux]</title><link>http://www.cppblog.com/klsmlzm/archive/2006/04/21/6026.html</link><dc:creator>牵牛散步</dc:creator><author>牵牛散步</author><pubDate>Fri, 21 Apr 2006 07:06:00 GMT</pubDate><guid>http://www.cppblog.com/klsmlzm/archive/2006/04/21/6026.html</guid><wfw:comment>http://www.cppblog.com/klsmlzm/comments/6026.html</wfw:comment><comments>http://www.cppblog.com/klsmlzm/archive/2006/04/21/6026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/klsmlzm/comments/commentRss/6026.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/klsmlzm/services/trackbacks/6026.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#000000">对动态链接库的概念其实还很模糊,自己的理解是:<br />把一些常用的代码,如函数,类等,编译成一个"包"即DLL(WINDOWS下)或者SO(LINUX下)文件,<br />然后供其它程序使用时直接调用里面封闭的函数即可,实现的代码的重用,也节省了<br />硬盘空间(这点可能是次要的吧).在WIDOWS下利用VC++可方便的生成DLL,在LINUX下则需要通过<br />各种编译命令来实现,对于像我这种菜鸟级程序员来说是个不小的挑战.<br />下面用个简单的例子来说明生成一个.SO文件和如何使用它:<br />1.我这有几个文件:<br />ConfigMap.cpp ConfigMap.h (读配置文件类)GetWinState.cpp GetWinState.h(ICE接口文件,由SLICE生成) GetWinSysState.cpp GetWinSysState.h (远程接口实现文件)<br />SocDbInfo.cpp(封装的一个类,用于调用ICE接口实现相关操作)<br />说明:此程序是为了获得远程主机(WINDOWS)上一些系统信息,比如:CPU占用率,硬盘使用情况,数据<br />库连接状态,内存使用情况等.<br />我想利用这些文件生成动态链接库.SO,主要是调用SocDbInfo.cpp里的类.然后可以拿到任意一个系统中(LINUX)去用.<br />2.开始编译:$c++ -I. -I$ICE_HOME/include -c *.cpp<br />编译后生成连接文件(我一直这样叫,可能不对哈),即以.O结尾的<br />3.生成动态链接库:$c++ -shared -o libMyApp.so *.o -L$ICE_HOME/lib -lIce -lIceUtil<br />这样就生成了libMyApp.so文件,即我们所要的<br />4.使用动态链接库:<br />新建两个文件Demo.cpp Demo.h(使用libMyApp.so提供的一些函数),<br />在Demo.h中声明了libMyApp.so中提供的函数和结构体,<br />Demo.h:代码如下:<br /><br />struct MemoryInf<br />{<br /> int TotalMem;//×ÜÄÚ´æ´óÐ¡<br /> int ValidMem;//¿ÉÊ¹ÓÃÄÚ´æ´óÐ¡<br /> int VirtualMem;//ÐéÄâÄÚ´æ´óÐ¡<br />};<br />struct DiskInf<br />{<br /> int TotalSpace;//Ó²ÅÌ´óÐ¡<br /> int FreeSpace;//Ê£Óà¿Õ¼ä´óÐ¡<br />};<br />struct DbInf<br />{<br /> int DbStat;//Êý¾Ý¿â×´Ì¬:"0"±íÊ¾Êý¾Ý¿â´¦ÔÚ¹Ø±Õ×´Ì¬,"1"±íÊ¾Êý¾Ý¿âÕý³£´ò¿ª,"2"±íÊ¾Êý¾Ý¿â´¦ÔÚ¹ÒÆð×´Ì¬<br /> int DbConnNum;//Êý¾Ý¿âÁ¬½ÓÊý<br />};<br />bool Inital( char *ResHostIP);//³õÊ¼»¯Í¨ÐÅÆ÷<br />bool DesIceCom();//Ïú»ÙICEÍ¨ÐÅÆ÷<br />MemoryInf GetMemInf();//µÃµ½ÄÚ´æÐÅÏ¢<br />int GetCpuInf();//µÃµ½CPUÕ¼ÓÃÂÊ<br />DbInf GetDbStat();//µÃµ½Êý¾Ý¿âÐÅÏ¢<br />DiskInf GetDiskStat();//µÃµ½Ó²ÅÌÐÅÏ¢</font>
		</p>
		<font color="#000000">
				<p>
						<br />
						<br />注:乱码是由于我的LINUX下不支持中文哈,是注释不用管它<br />Demo.cpp:代码如下:<br />#include &lt;string.h&gt;<br />#include &lt;iostream&gt;<br />#include "Demo.h"</p>
				<p>
						<br />int main( int argc , char* argv[])<br />{</p>
				<p> MemoryInf mymem;<br /> DiskInf mydisk;<br /> DbInf mydb;<br /> Inital( argv[1]);<br /> mydisk = GetDiskStat();<br /> mymem = GetMemInf();<br /> mydb = GetDbStat();<br /> printf("disk total space:%d\n",mydisk.TotalSpace);<br /> printf("disk FreeSpace space:%d\n",mydisk.FreeSpace);<br /> printf("Memory TotalMem:%d\n",mymem.TotalMem);<br /> printf("ValidMem:%d\n",mymem.ValidMem);<br /> printf("VirtualMem:%d\n",mymem.VirtualMem);<br /> printf("DbConnNum:%d\n",mydb.DbConnNum);<br /> printf("DbStat:%d\n",mydb.DbStat);<br /> printf("cpu:%d\n",GetCpuInf());<br /> DesIceCom();<br /> return 1;<br />}<br /><br /><br />5.编译文件生成可执行程序:<br />用以下命令:<br />$c++ -lMyApp -o Demo Demo.cpp<br />说明:-lMyApp参数表示,用动态链接库libMyApp.so一起进行编译,对了libMyApp.so最好放在/usr/lib目录下哈<br />如不出意外刚会生成名为Demo的可执行文件<br /><br /></p>
		</font>
<img src ="http://www.cppblog.com/klsmlzm/aggbug/6026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/klsmlzm/" target="_blank">牵牛散步</a> 2006-04-21 15:06 <a href="http://www.cppblog.com/klsmlzm/archive/2006/04/21/6026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载:学习ICE 3.0--Slice语言</title><link>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1712.html</link><dc:creator>牵牛散步</dc:creator><author>牵牛散步</author><pubDate>Tue, 13 Dec 2005 04:00:00 GMT</pubDate><guid>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1712.html</guid><wfw:comment>http://www.cppblog.com/klsmlzm/comments/1712.html</wfw:comment><comments>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1712.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/klsmlzm/comments/commentRss/1712.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/klsmlzm/services/trackbacks/1712.html</trackback:ping><description><![CDATA[<DIV class=sect1 lang=zh-cn xml:lang="zh-cn">
<DIV class=titlepage>
<DIV>
<DIV>
<H2 class=title style="CLEAR: both"><A id=id353466></A>Slice语言</H2></DIV></DIV></DIV>
<P>首先，请大家读ICE中文手册中的Slice语言一章。 这一部分除了model（模块），在 ICE 1.3中文手册中都有描述 </P>
<DIV class=figure><A id=id353476></A>
<P class=title><B>图&nbsp;2.1.&nbsp;ice网络编程示意图(服务器端和客户端采用同种编程语言C＋＋)</B></P>
<DIV class=mediaobject><IMG alt=ice网络编程示意图(服务器端和客户端采用同种编程语言C＋＋) src="http://enjoylanguage.sourceforge.net/picture/figures/ice_slice.png"></DIV></DIV>
<DIV class=figure><A id=id354595></A>
<P class=title><B>图&nbsp;2.2.&nbsp;ice网络编程示意图(服务器端和客户端采用不同编程语言)</B></P>
<DIV class=mediaobject><IMG alt=ice网络编程示意图(服务器端和客户端采用不同编程语言) src="http://enjoylanguage.sourceforge.net/picture/figures/ice_slice_java_and_cpp.png"></DIV></DIV>
<DIV class=sect2 lang=zh-cn xml:lang="zh-cn">
<DIV class=titlepage>
<DIV>
<DIV>
<H3 class=title><A id=id354616></A>基础知识</H3></DIV></DIV></DIV>
<P>含有Slice 定义的文件必须以.ice 扩展名结尾，例如， Clock.ice就是一个有效的文件名。编译器拒绝接受其他扩展名。 </P>
<P>Slice 支持#ifndef、#define、#endif，以及#include 预处理指令。它们的使用方式有严格的限制：你只能把#ifndef、#define，以及#endif 指令用于创建双包括（double-include）块。例如： </P><PRE class=programlisting>#ifndef _CLOCK_ICE
#define _CLOCK_ICE
// #include 文件 here...
//定义 here...
#endif _CLOCK_ICE
</PRE>
<P>我们强烈建议你在所有的Slice 定义中使用双包括（double-include）块（所上），防止多次包括同一文件。 </P>
<P>#include 指令只能出现在Slice 源文件的开头，也就是说，它们必须出现在其他所有Slice 定义的前面。此外，在使用#include 指令时，只允许使用&lt;&gt; 语法来指定文件名，不能使用""。例如： </P><PRE class=programlisting> #include &lt;File1.ice&gt; // OK
#include "File2.ice" // 不支持!
</PRE>
<P>你不能把这些预处理指令用于其他目的，也不能使用其他的C++ 预处理指令 （比如用\ 字符来连接行、token 粘贴，以及宏展开，等等）。 </P>
<P>在Slice 定义里，既可以使用C 的、也可以使用C++ 的注释风格： </P>
<P>Slice 关键字必须小写。例如， class 和dictionary 都是关键字，必须按照所示方式拼写。这个规则有两个例外：Object 和LocalObject 也是关键字，必须按照所示方式让首字母大写。 </P>
<P>标识符以一个字母起头，后面可以跟任意数目的字母或数字。Slice 标识符被限制在ASCII 字符范围内，不能包含非英语字母，与C++ 标识符不同， Slice 标识符不能有下划线。这种限制初看上去显得很苛刻，但却是必要的：保留下划线，各种语言映射就获得了一个名字空间，不会与合法的Slice 标识符发生冲突。于是，这个名字空间可用于存放从Slice 标识符派生的原生语言标识符，而不用担心其他合法的Slice 标识符会碰巧与之相同，从而发生冲突 。 </P>
<P>标识符（变量名等等）是大小写不敏感的，但大小写的拼写方式必须保持一致（看了后面的话，再理解一下）。例如，在一个作用域内， TimeOfDay 和TIMEOFDAY 被认为是同一个标识符。但是，Slice 要求你保持大小写的一致性。在你引入了一个标识符之后，你必须始终一致地拼写它的大写和小写字母；否则，编译器就会将其视为非法而加以拒绝。这条规则之所以存在，是要让Slice 既能映射到忽略标识符大小写的语言，又能映射到把大小写不同的标识符当作不同标识符的语言。（可以这样理解，变量名区分大小写，并且不可以是相同的单词） </P>
<P>是关键字的标识符:你可以定义在一种或多种实现语言中是关键字的Slice 标识符。例如，switch是完全合法的Slice标识符，但也是C++和Java的关键字。语言映射定义了一些规则来处理这样的标识符。要解决这个问题，通常要用一个前缀来使映射后的标识符不再是关键字。例如， Slice 标识符switch 被映射到C++ 的_cpp_switch ，以及Java 的_switch。对关键字进行处理的规则可能会产生难以阅读的源码。像native、throw，或export 这样的标识符会与C++ 或Java（或两者）的关键字发生冲突。为了让你和别人生活得更轻松一点，你应该避免使用是实现语言的关键字的Slice 标识符。要记住，以后Ice 可能会增加除C++ 和Java 以外的语言映射。尽管期望你总结出所有流行的编程语言的所有关键字并不合理，你至少应该尽量避免使用常用的关键字。使用像self、import，以及while 这样的标识符肯定不是好主意。 </P>
<P>转义的标识符:在关键字的前面加上一个反斜线，你可以把Slice 关键字用作标识符，例如: </P><PRE class=programlisting>struct dictionary { // 错误!
// ...
};
struct \dictionary { // OK
// ...
};
</PRE>
<P>反斜线会改变关键字通常的含义；在前面的例子中， \dictionary 被当作标识符dictionary。转义机制之所以存在，是要让我们在以后能够在Slice 中增加关键字，同时尽量减少对已有规范的影响：如果某个已经存在的规范碰巧使用了新引入的关键字，你只需在新关键字前加上反斜线，就能够修正该规范。注意，从风格上说，你应该避免用Slice 关键字做标识符（即使反斜线转义允许你这么做）。 </P>
<P>保留的标识符:Slice 为Ice 实现保留了标识符Ice 及以Ice （任何大小写方式）起头的所有标识符。例如，如果你试图定义一个名为Icecream 的类型， Slice 编译器会发出错误警告3。以下面任何一种后缀结尾的Slice 标识符也是保留的：Helper、Holder、Prx，以及Ptr。Java 和C++ 语言映射使用了这些后缀，保留它们是为了防止在生成的代码中发生冲突。 </P>
<P>（注：ICE 1.3的中文手册上没有“模块”这一部分）模块来组织一组相关的语句是为了解决名字冲突。模块可以包含所有合法的Slice语句和子模块。你可以用一些不常用的词来给最外层的模块命名，比如公司名、产品名等等。 </P><PRE class=programlisting>module ZeroC {

	module Client {
	// Definitions here...
	};

	module Server {
	// Definitions here...
	};
};
</PRE>
<P></P>
<P>Slice要求所有的定义都是模块的一部分，比如，下面的语句就是非法的。 </P><PRE class=programlisting>interface I { // 错误:全局空间中只可以有模块
// ...
};
</PRE>
<P></P>
<P>多个文件可以共享同一个模块，比如： </P><PRE class=programlisting>module ZeroC {
// Definitions here...
};

//另一个文件中 :
module ZeroC { // OK, reopened module
// More definitions here...
};
</PRE>
<P></P>
<P>把一个大的模块放到几个文件中去可以方便编译（你只需重新编译被修改的文件，而没有必要编译整个模块）。 </P>
<P>模块将映射的语言中的相应结构，比如 C++, C#, 和 Visual Basic, Slice的modules被映射为namespaces；java中被映射为package. </P>
<P>除了少数与特定的程序语言相关的调用之外，ice的绝大部分API（应用程序接口）都是用Slice来定义的 。这样做的好处是可以用一个ICE API定义文件来支持所有的程序语言。 </P>
<DIV class=note style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
<TABLE summary=Note border=0>
<TBODY>
<TR>
<TD vAlign=top align=middle width=25 rowSpan=2><IMG alt=[注意] src="http://enjoylanguage.sourceforge.net/picture/images/note.png"></TD>
<TH align=left>注意</TH></TR>
<TR>
<TD vAlign=top align=left>为了保证代码的简洁，以后文章中提及的Slice定义没有写出包含的模块，你要假定该语句是在一个模块中。 </TD></TR></TBODY></TABLE></DIV>
<DIV class=table><A id=id370009></A>
<P class=title><B>表&nbsp;2.1.&nbsp;Slice的数据类型</B></P>
<TABLE summary=Slice的数据类型 border=1>
<COLGROUP>
<COL>
<COL>
<COL></COLGROUP>
<THEAD>
<TR>
<TH>类型</TH>
<TH>取值范围</TH>
<TH>大小（单位：bit）</TH></TR></THEAD>
<TBODY>
<TR>
<TD>bool</TD>
<TD>false or true</TD>
<TD>≥ 1</TD></TR>
<TR>
<TD>byte</TD>
<TD>-128-127或0-255</TD>
<TD>≥ 8</TD></TR>
<TR>
<TD>short</TD>
<TD>2<SUP>－15</SUP>至2<SUP>15</SUP>－1</TD>
<TD>≥ 16</TD></TR>
<TR>
<TD>int</TD>
<TD>2<SUP>－31</SUP>至2<SUP>31</SUP>－1</TD>
<TD>≥ 32</TD></TR>
<TR>
<TD>long</TD>
<TD>2<SUP>－63</SUP>至2<SUP>63</SUP>－1</TD>
<TD>≥ 64</TD></TR>
<TR>
<TD>float</TD>
<TD>IEEE的单精度</TD>
<TD>≥ 32 bits</TD></TR>
<TR>
<TD>double</TD>
<TD>IEEE的双精度</TD>
<TD>≥ 64 bits</TD></TR>
<TR>
<TD>string</TD>
<TD>所有Unicode 字符，除了所有位为零的字符</TD>
<TD>变长</TD></TR></TBODY></TABLE></DIV></DIV>
<DIV class=sect2 lang=zh-cn xml:lang="zh-cn">
<DIV class=titlepage>
<DIV>
<DIV>
<H3 class=title><A id=id388821></A>用户定义的类型</H3></DIV></DIV></DIV>
<DIV class=itemizedlist>
<UL type=disc>
<LI>
<P>枚举:enum Fruit { Apple, Pear, Orange }; </P>
<P>这个定义引入了一种名为Fruit 的类型，这是一种拥有自己权利的新类型。关于怎样把顺序值（ordinal values）赋给枚举符的问题， Slice 没有作出定义。例如，你不能假定，在各种实现语言中，枚举符Orange 的值都是2。Slice 保证枚举符的顺序值会从左至右递增，所以在所有实现语言中，Apple 都比Pear 要小。与C++ 不同， Slice 不允许你控制枚举符的顺序值（因为许多实现语言不支持这种特性）： </P><PRE class=programlisting>enum Fruit { Apple = 0, Pear = 7, Orange = 2 }; // 出错
</PRE>
<P>在实践中，只要你不在地址空间之间传送枚举符的顺序值，你就不用管枚举符使用的值是多少。例如，发送值0 给服务器来表示Apple 可能会造成问题，因为服务器可能没有用0 表示Apple。相反，你应该就发送值Apple 本身。如果在接收方的地址空间中， Apple 是用另外的顺序值表示的， Ice run time 会适当地翻译这个值。 </P>
<P>与在C++ 里一样， Slice 枚举符也会进入围绕它的名字空间，所以下面的定义是非法的： </P><PRE class=programlisting>enum Fruit { Apple, Pear, Orange };
enum ComputerBrands { Apple, IBM, Sun, HP }; // Apple已经被定义!
</PRE>
<P>Slice 不允许定义空的枚举。 </P>
<LI>
<P>结构</P>Slice 支持含有一个或多个有名称的成员的结构，这些成员可以具有任意类型，包括用户定义的复杂类型。例如： <PRE class=programlisting>struct TimeOfDay {
short hour; // 0 - 23
short minute; // 0 - 59
short second; // 0 - 59
};
</PRE>与在 C++ 里一样，这个定义引入了一种叫作TimeOfDay 的新类型。结构定义会形成名字空间，所以结构成员的名字只需在围绕它们的结构里是唯一的。在结构内部，只能出现数据成员定义，这些定义必须使用有名字的类型。例如，你不可能在结构内定义结构： <PRE class=programlisting>struct TwoPoints {
struct Point { //错误!
short x;
short y;
};
Point coord1;
Point coord2;
};
</PRE>这个规则大体上适用于Slice：类型定义不能嵌套（除了模块支持嵌套）。其原因是，对于某些目标语言而言，嵌套的类型定义可能会难以实现，而且，即使能够实现，也会极大地使作用域解析规则复杂化。对于像Slice 这样的规范语言而言，嵌套的类型定义并无必要——你总能以下面的方式编写上面的定义（这种方式在风格上也更加整洁）： <PRE class=programlisting>struct Point {
short x;
short y;
};
struct TwoPoints { // Legal (and cleaner!)
Point coord1;
Point coord2;
}
</PRE>
<LI>
<P>序列</P>
<P>序列是变长的元素向量： </P><PRE class=programlisting>sequence&lt;Fruit&gt; FruitPlatter;
</PRE>
<P></P>序列可以是空的——也就是说，它可以不包含元素；它也可以持有任意数量的元素，直到达到你的平台的内存限制。 
<P></P>序列包含的元素自身也可以是序列。这种设计使得你能够创建列表的列表： 
<P></P><PRE class=programlisting>sequence&lt;FruitPlatter&gt; FruitBanquet;
</PRE>
<P>序列可用于构建许多种collection，比如向量、列表、队列、集合、包（bag），或是树（次序是否重要要由应用决定；如果无视次序，序列充当的就是集合和包）。 </P>
<P>序列的一种特别的用法已经成了惯用手法，即用序列来表示可选的值。例如，我们可能拥有一个Part 结构，用于记录小汽车的零件的详细资料。这个结构可以记录这样的资料：零件名称、描述、重量、价格，以及其他详细资料。 备件通常都有序列号，我们用一个long 值表示。但有些零件，比如常用的螺丝钉，常常没有序列号，那么我们在螺丝钉的序列号字段里要放进什么内容？要处理这种情况，有这样一些选择： </P>
<DIV class=itemizedlist>
<UL type=circle>
<LI>
<P>用一个标记值，比如零，来指示“没有序列号”的情况。 </P>
<P>这种方法是可行的，只要确实有标记值可用。尽管看起来不大可能有人把零用作零件的序列号，这并非是不可能的。而且，对于其他的值，比如温度值，在其类型的范围中的所有值都可能是合法的，因而没有标记值可用。 </P>
<LI>
<P>把序列号的类型从long 变成string。 </P>
<P>串自己有内建的标记值，也就是空串，所以我们可以用空串来指示.“没有序列号”的情况。这也是可行的，但却会让大多数人感到不快：我们不应该为了得到一个标记值，而把某种事物自然的数据类型变成string </P>
<LI>
<P>增加一个指示符来指示序列号的内容是否有效. </P>
<P></P><PRE class=programlisting>struct Part {
string name;
string description;
// ...
bool serialIsValid; // true if part has serial number
long serialNumber;
};
</PRE>
<P></P>
<P>对于大多数人而言，这也让人讨厌，而且最终肯定会让你遇到麻烦：迟早会有程序员忘记在使用序列号之前检查它是否有效，从而带来灾难性的后果。 </P>
<LI>
<P>用序列来建立可选字段 </P>
<P>这种技术使用了下面的惯用手法： </P><PRE class=programlisting>sequence&lt;long&gt; SerialOpt;
struct Part {
string name;
string description;
// ...
SerialOpt serialNumber; // optional: zero or one element
};
</PRE>
<P>按照惯例， Opt 后缀表示这个序列是用来建立可选值的。如果序列是空的，值显然就不在那里；如果它含有一个元素，这个元素就是那个值。这种方案明显的缺点是，有人可能会把不止一个元素放入序列。为可选值增加一个专用的Slice 成分可以纠正这个问题。但可选值并非那么常用，不值得为它增加一种专门的语言特性（我们将看到，你还可以用类层次来建立可选字段）。 </P></LI></UL></DIV>
<P></P>
<LI>
<P>词典</P>
<P>词典是从键类型到值类型的映射。例如： </P><PRE class=programlisting>struct Employee {
long number;
string firstName;
string lastName;
};
dictionary&lt;long, Employee&gt; EmployeeMap;
</PRE>
<P>这个定义创建一种叫作EmployeeMap 的词典，把雇员号映射到含有雇员详细资料的结构。你可以自行决定键类型（在这个例子中是long 类型的雇员号）是否是值类型（在这个例子中是Employee 结构）的一部分——就Slice 而言，你无需让键成为值的一部分。 </P>
<P>词典可用于实现稀疏数组，或是具有非整数键类型的任何用于查找的数据结构。尽管含有键－值对的结构的序列可用于创建同样的事物，词典要更为适宜： </P>
<DIV class=itemizedlist>
<UL type=circle>
<LI>
<P>词典明确地表达了设计者的意图，也就是，提供从值的域（domain）到值的范围（range）的映射（含有键－值对的结构的序列没有如此明确地表达同样的意图）。 </P>
<LI>
<P>在编程语言一级，序列被实现成向量（也可能是列表），也就是说，序列不大适用于内容稀疏的域，而且要定位具有特定值的元素，需要进行线性查找。而词典被实现成支持高效查找的数据结构（通常是哈希表或红黑树），其平均查找时间是O(log n)，或者更好。词典的键类型无需为整型。例如，我们可以用下面的定义来翻译一周每一天的名称： </P><PRE class=programlisting>dictionary&lt;string, string&gt; WeekdaysEnglishToGerman;
</PRE>
<P>服务器实现可以用键－值对Monday–Montag、Tuesday–Dienstag，等等，对这个映射表进行初始化。 </P>
<LI>
<P>词典的值类型可以是用户定义的任何类型。但词典的键类型只能是以下类型之一： </P>
<DIV class=itemizedlist>
<UL type=square>
<LI>
<P>整型（byte、short、int、long、bool，以及枚举类型） </P>
<LI>
<P>string </P>
<LI>
<P>元素类型为整型或string 的序列 </P>
<LI>
<P>数据成员的类型只有整型或string 的结构 </P></LI></UL></DIV>
<P>复杂的嵌套类型，比如嵌套的结构或词典，以及浮点类型（float和double），不能用作键类型。之所以不允许使用复杂的嵌套类型，是因为这会使词典的语言映射复杂化；不允许使用浮点类型，是因为浮点值在跨越机器界线时，其表示会发生变化，有可能导致成问题的相等语义。 </P></LI></UL></DIV>
<P></P>
<LI>
<P>常量定义与直接量</P>
<P>Slice 允许你定义常量。常量定义的类型必须是以下类型中的一种： </P>
<DIV class=itemizedlist>
<UL type=circle>
<LI>
<P>整型（bool、byte、short、int、long，或枚举类型） </P>
<LI>
<P>float 或double </P>
<LI>
<P>string </P></LI></UL></DIV>
<P>下面有一些例子： </P><PRE class=programlisting>const bool AppendByDefault = true;
const byte LowerNibble = 0x0f;
const string Advice = "Don't Panic!";
const short TheAnswer = 42;
const double PI = 3.1416;
enum Fruit { Apple, Pear, Orange };
const Fruit FavoriteFruit = Pear;
</PRE>
<P></P>
<P>直接量（literals）的语法与C++ 和Java 的一样（有一些小的例外）： </P>
<DIV class=itemizedlist>
<UL type=circle>
<LI>
<P>布尔常量只能用关键字false和true初始化（你不能用0和1来表示false和true）。 </P>
<LI>
<P>和C++ 一样，你可以用十进制、八进制，或十六进制方式来指定整数直接量。例如： </P><PRE class=programlisting>const byte TheAnswer = 42;
const byte TheAnswerInOctal = 052;
const byte TheAnswerInHex = 0x2A; // or 0x2a
</PRE>
<P></P>
<DIV class=note style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
<TABLE summary=Note border=0>
<TBODY>
<TR>
<TD vAlign=top align=middle width=25 rowSpan=2><IMG alt=[注意] src="http://enjoylanguage.sourceforge.net/picture/images/note.png"></TD>
<TH align=left>注意</TH></TR>
<TR>
<TD vAlign=top align=left>如果你把byte 解释成数字、而不是位模式，你在不同的语言里可能会得到不同的结果。例如，在C++ 里， byte 映射到char，取决于目标平台， char 可能是有符号的，也可能是无符号的。</TD></TR></TBODY></TABLE></DIV>
<DIV class=note style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
<TABLE summary=Note border=0>
<TBODY>
<TR>
<TD vAlign=top align=middle width=25 rowSpan=2><IMG alt=[注意] src="http://enjoylanguage.sourceforge.net/picture/images/note.png"></TD>
<TH align=left>注意</TH></TR>
<TR>
<TD vAlign=top align=left>用于指示长常量和无符号常量的后缀（C++ 使用的l、L、u、U）是非法的： <PRE class=programlisting>const long Wrong = 0u; // Syntax error
const long WrongToo = 1000000L; // Syntax error
</PRE></TD></TR></TBODY></TABLE></DIV>
<LI>
<DIV class=itemizedlist>
<UL type=square>
<LI>
<P>整数直接量的值必须落在其常量类型的范围内，否则编译器就会发出诊断消息。 </P>
<LI>
<P>浮点直接量使用的是C++语法，除了你不能用l或L后缀来表示扩展的浮点常量；但是， f 和F 是合法的（但会被忽略）。下面是一些例子： </P><PRE class=programlisting>const float P1 = -3.14f; // Integer &amp; fraction, with suffix
const float P2 = +3.1e-3; // Integer, fraction, and exponent
const float P3 = .1; // Fraction part only
const float P4 = 1.; // Integer part only
const float P5 = .9E5; // Fraction part and exponent
const float P6 = 5e2; // Integer part and exponent
</PRE>
<P></P>
<LI>
<P>浮点直接量必须落在其常量类型（float 或double）的范围内；否则编译器会发出诊断警告。 </P>
<LI>
<P>串直接量支持与C++ 相同的转义序列。下面是一些例子： </P><PRE class=programlisting>const string AnOrdinaryString = "Hello World!";
const string DoubleQuote = "\"";
const string TwoSingleQuotes = "'\'"; // ' and \' are OK
const string Newline = "\n";
const string CarriageReturn = "\r";
const string HorizontalTab = "\t";
const string VerticalTab = "\v";
const string FormFeed = "\f";
const string Alert = "\a";
const string Backspace = "\b";
const string QuestionMark = "\?";
const string Backslash = "\\";
70 Slice 语言
const string OctalEscape = "\007"; // Same as \a
const string HexEscape = "\x07"; // Ditto
const string UniversalCharName = "\u03A9"; // Greek Omega
和在 C++ 里一样，相邻的串直接量会连接起来：
const string MSG1 = "Hello World!";
const string MSG2 = "Hello" " " "World!"; // Same message
/*
* Escape sequences are processed before concatenation,
* so the string below contains two characters,
* '\xa' and 'c'.
*/
const string S = "\xa" "c";
</PRE>
<P></P>
<DIV class=note style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
<TABLE summary=Note border=0>
<TBODY>
<TR>
<TD vAlign=top align=middle width=25 rowSpan=2><IMG alt=[注意] src="http://enjoylanguage.sourceforge.net/picture/images/note.png"></TD>
<TH align=left>注意</TH></TR>
<TR>
<TD vAlign=top align=left>Slice 没有null 串的概念 <PRE class=programlisting>const string nullString = 0; // Illegal!
</PRE>null 串在Slice 里根本不存在，因此，在Ice 平台的任何地方它都不能用作合法的串值。这一决定的原因是， null 串在许多编程语言里不存在</TD></TR></TBODY></TABLE></DIV></LI></UL></DIV></LI></UL></DIV>
<P></P></LI></UL></DIV></DIV>
<DIV class=sect2 lang=zh-cn xml:lang="zh-cn">
<DIV class=titlepage>
<DIV>
<DIV>
<H3 class=title><A id=id420824></A>接口、操作，以及异常</H3></DIV></DIV></DIV>
<P>见手册........抄书好累......... </P></DIV></DIV><img src ="http://www.cppblog.com/klsmlzm/aggbug/1712.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/klsmlzm/" target="_blank">牵牛散步</a> 2005-12-13 12:00 <a href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1712.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载:学习ICE 3.0--初读代码</title><link>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1711.html</link><dc:creator>牵牛散步</dc:creator><author>牵牛散步</author><pubDate>Tue, 13 Dec 2005 03:58:00 GMT</pubDate><guid>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1711.html</guid><wfw:comment>http://www.cppblog.com/klsmlzm/comments/1711.html</wfw:comment><comments>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1711.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/klsmlzm/comments/commentRss/1711.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/klsmlzm/services/trackbacks/1711.html</trackback:ping><description><![CDATA[<DIV class=sect1 lang=zh-cn xml:lang="zh-cn">
<DIV class=titlepage>
<DIV>
<DIV>
<H2 class=title style="CLEAR: both"><A id=id353427></A>初读代码</H2></DIV></DIV></DIV>
<P>这一节大部分内容整理自ICE中文手册，在这里我特别感谢马维达同志的翻译给我们的学习带来了方便。 </P>
<P>读服务端代码</P>
<P><B>文件server.cpp.&nbsp;</B></P><PRE class=programlisting>#include &lt;Ice/Ice.h&gt; 		
#include "../print.h"
using namespace std;
using namespace Demo;

//惯例，用后缀I 表示这个类实现一个接口
class PrinterI : public Printer {
public:
	virtual void printString(const string&amp; s, const Ice::Current&amp;);
};	 
/*
打开print.h，看看PrinterI父类的定义

namespace Demo {
class Printer : virtual public Ice::Object {
public:

//纯虚函数，不能实例化
virtual void printString(const std::string&amp;,
//第二个参数有缺省值，实现中可以不使用
const Ice::Current&amp;= Ice::Current()) = 0;
};
};
*/

void PrinterI::printString(const string&amp; s, const Ice::Current&amp;)
{
	cout &lt;&lt; s &lt;&lt; endl;
}

int  main(int argc, char* argv[])
{	
	//程序的退出时的状态，就是否成功执行
	int status = 0; 

	 //来包含Ice run time 的主句柄	(main handle)
	Ice::CommunicatorPtr ic;

	try {
	//初始化Ice run time （argc和argv是run time命令参数；
	//就这个例子而言，服务器不需要任何命令行参数）。
    //initialize 返回一个指向Ice::Communicator对象的智能指针，
	//这个指针是Ice run time 的主句柄。
		ic = Ice::initialize(argc, argv);
	 
	 //调用Communicator 实例上的createObjectAdapterWithEndpoints，
	 //创建一个对象适配器(比如：网卡就是一种适配器)。
	 //参数是"SimplePrinterAdapter" （适配器的名字）
	 //和"default -p 10000"(用缺省协议（TCP/IP）,侦听端口10000 的请求。)
	 //显然，在应用中硬编码对象标识和端口号，是一种糟糕的做法，
	 //但它目前很有效；我们将在以后看到在架构上更加合理的做法。
		Ice::ObjectAdapterPtr adapter
			= ic-&gt;createObjectAdapterWithEndpoints(
			"SimplePrinterAdapter", "default -p 10000");

	  //服务器端run time 已经初始化,实例化一个PrinterI 对象，
	  //为我们的Printer 接口创建一个servant（serv 服务＋-ant人,背一下单词）。
		Ice::ObjectPtr object = new PrinterI;

	  //我们调用适配器的add，告诉它有了一个新的servant ；
	  //传给add 的参数是刚才实例化的servant，再加上一个标识符。
	  //在这里，"SimplePrinter" 串是servant 的名字
	  //（如果我们有多个打印机，每个打印机都可以有不同的名字，
	  //更正确的说法是，都有不同的对象标识）。
		adapter-&gt;add(object,
			Ice::stringToIdentity("SimplePrinter"));

		//调用适配器的activate 方法激活适配器
		//（适配器一开始是在暂停（holding）状态创建的；
		//这种做法在下面这样的情况下很有用：
		//我们有多个servant，它们共享同一个适配器，
		//而在所有servant实例化之前我们不想处理请求）。
		//一旦适配器被激活，服务器就会开始处理来自客户的请求。
		adapter-&gt;activate();

		//最后，我们调用waitForShutdown。
		//这个方法挂起发出调用的线程直到服务器实现终止
		//——或者是通过发出一个调用关闭run time，
		ic-&gt;waitForShutdown();
	} 
	catch (const Ice::Exception&amp; e) {
			cerr &lt;&lt; e &lt;&lt; endl;
		status = 1;
	} catch (const char* msg) {
		cerr &lt;&lt; msg &lt;&lt; endl;
		status = 1;
	}
	if (ic) {
		try {

		//必须调用Communicator::destroy结束Ice run time。
		//destroy 会等待任何还在运行的操作调用完成。
		//此外， destroy 还会确保任何还未完成的线程都得以汇合（joined），
		//并收回一些操作系统资源，比如文件描述符和内存。
		//决不要让你的main 函数不调用destroy 就终止,
		//否则，后果无法想象。
			ic-&gt;destroy();

		} catch (const Ice::Exception&amp; e) {
			cerr &lt;&lt; e &lt;&lt; endl;
			status = 1;
		}
	}
	return status;
}
</PRE>
<P>注意，尽管以上的代码不算少，但它们对所有的服务器都是一样的。你可以把这些代码放在一个辅助类里，然后就无需再为它费心了（Ice 提供了这样的辅助类，叫作Ice::Application，参见 10.3.1 节） 。就实际的应用代码而言，服务器只有几行代码：六行代码定义PrinterI 类，再加上三2 行代码实例化一个PrinterI 对象，并向对象适配器注册它。 </P>
<P>读客户端代码</P>
<P><B>文件client.cpp.&nbsp;</B></P><PRE class=programlisting>#include &lt;Ice/Ice.h&gt;
#include "..\print.h"
using namespace std;
using namespace Demo;
int main(int argc, char* argv[])
{
	int status = 0;
	Ice::CommunicatorPtr ic;
	try {
		ic = Ice::initialize(argc, argv);

		//stringToProxy 返回的代理（Proxy）类型是Ice::ObjectPrx，
		//这种类型位于接口和类的继承树的根部（接口的基类）。
		 Ice::ObjectPrx base 
		=ic-&gt;stringToProxy(	"SimplePrinter:default -p 10000");

		//但要实际要与我们的打印机交谈，
		//我们需要的是Printer 接口、不是Object 接口的代理。
		//为此，需要调用PrinterPrx::checkedCast 进行向下转换（向下转型）。
		//这个方法会发送一条消息给服务器，
		//询问“这是Printer 接口的代理吗？”
		//如果回答“是”，就会返回Printer 的一个代理；
		//如果代理代表的是其他类型的接口，返回一个空代理
		PrinterPrx printer = PrinterPrx::checkedCast(base);
		
		//测试向下转型是否成功，若不成功，就抛出出错消息并终止客户。
		if (!printer) 	throw "Invalid proxy";

		//现在，我们在我们的地址空间里有了一个激活的代理，
		//可以调用printString 方法，
		//把享誉已久的 "Hello World!" 串传给它。
		//服务器会在它的终端上打印这个串。
		printer-&gt;printString("Hello World!");
	}
	catch (const Ice::Exception&amp; ex) {
		cerr &lt;&lt; ex &lt;&lt; endl;
		status = 1;
	} catch (const char* msg) {
		cerr &lt;&lt; msg &lt;&lt; endl;
		status = 1;
	}
	if (ic)
		ic-&gt;destroy();
	return status;
}
</PRE>
<P>如果出现任何错误，客户会打印一条出错消息。例如，如果我们没有先启动服务器就运行客户，我们会得到： </P><PRE class=screen>Network.cpp:471: Ice::ConnectFailedException:
connect failed: Connection refused
</PRE>
<P>(由于windows下的命令行窗口在出错后会一闪就消失，不过我们可以在client.cpp的main函数的return status;之前加上system("PAUSE");然后再在VS2003.net中把client设置为启动项目，重新编译，运行。OK，可以看到结果了。) </P></DIV><img src ="http://www.cppblog.com/klsmlzm/aggbug/1711.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/klsmlzm/" target="_blank">牵牛散步</a> 2005-12-13 11:58 <a href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1711.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载:学习ICE 3.0--准备工作</title><link>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.html</link><dc:creator>牵牛散步</dc:creator><author>牵牛散步</author><pubDate>Tue, 13 Dec 2005 03:56:00 GMT</pubDate><guid>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.html</guid><wfw:comment>http://www.cppblog.com/klsmlzm/comments/1710.html</wfw:comment><comments>http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/klsmlzm/comments/commentRss/1710.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/klsmlzm/services/trackbacks/1710.html</trackback:ping><description><![CDATA[<DIV class=titlepage>
<DIV>
<DIV>
<H2 class=title style="CLEAR: both"><A id=id355116></A>准备工作</H2></DIV></DIV></DIV>
<P>按照某人的说法：跨平台的C＋＋网络编程ICE才是王道。于是，我学习ICE。 </P>
<P>ICE才出来两年，是“一种现代的面向对象中间件，可用于替代像CORBA或COM/DCOM/COM+这样的中间件。在易于学习的同时，它为各种有着苛刻的技术要求的应用提供了强大的网络基础设施。”Ice 3.0 已实现对C++, Java, Python, PHP, C# 及 Visual Basic 的支持。 </P>
<P>这里我就不多说了,大家可以参考这篇文章：《反叛之冰：Internet Communications Engine 》。大家可以下载的ICE的官方参考手册，有中文版，不过是1.3.0版, 英文的是3.0版。 </P>
<P>ICE是开源的，大家可以从源代码开始编译，不过较复杂，幸好有binary版本，比如我就是下载的VS2003.NET的安装包。安装完成之后按照安装目录下的Readme对IDE进行一下配置，比如VC7.1就是把ice的include加入VC7.1的引用文件目录,把ice的lib目录加入VC7.1的库文件目录。然后再把安装目录下的bin文件夹添加到系统的环境变量Path中，最后，把bin文件夹下的所有DLL文件都Copy到Windows安装目录下的System32文件夹下（win98下是System文件夹？）。 </P>
<P>ICE自定义了一种SLICE语言，目的是定义接口，作用主要应该是保持对象调用或者数据传输时的语言无关性。 </P>
<P>开发一个ICE应用程序可以分为三步: </P>
<DIV class=orderedlist>
<OL type=1>
<LI>
<P>写一个Slice定义, 并且编译它</P>
<LI>
<P>写服务端, 并编译它</P>
<LI>
<P>写客户端, 并编译它</P></LI></OL></DIV>
<P></P>
<P>OK，写一个小程序，实现客户发送要打印的文本给服务器，再由服务器把文本发给打印机（这里我们用屏幕显示替代）,这里对代码解读请见下一章，这里不多说。 </P>
<DIV class=orderedlist>
<OL type=1>
<LI>
<P>写一个Slice定义, 并且编译它：</P>
<P><B>文件Printer.ice.&nbsp;</B></P><PRE class=programlisting>module Demo {
interface Printer {
	void printString(string s);
	};
};
</PRE>
<P>这个文件很简单, 但需要注意, 在区分大小写的系统上, 扩展名一定是小写.</P>
<P>编译也很简单,首先确认你已将你的bin目录加到系统的环境变量Path中.然后把上面这个片断保存成Printer.ice, 最后执行slice2cpp Printer.ice, 执行后的结果应该是自动生成了printer.h和printer.cpp. </P>
<LI>
<P>写服务端, 并编译它</P>
<P><B>文件server.cpp.&nbsp;</B></P><PRE class=programlisting>#include &lt;Ice/Ice.h&gt; 
#include "../print.h"
using namespace std;
using namespace Demo;
class PrinterI : public Printer {
public:
	virtual void printString(const string&amp; s,const Ice::Current&amp;);
};
void PrinterI::printString(const string&amp; s, const Ice::Current&amp;)
{
	cout &lt;&lt; s &lt;&lt; endl;
}
int  main(int argc, char* argv[])
{
	int status = 0;
	Ice::CommunicatorPtr ic;
	try {
		ic = Ice::initialize(argc, argv);
		Ice::ObjectAdapterPtr adapter
			= ic-&gt;createObjectAdapterWithEndpoints(
			"SimplePrinterAdapter", "default -p 10000");
		Ice::ObjectPtr object = new PrinterI;
		adapter-&gt;add(object,
			Ice::stringToIdentity("SimplePrinter"));
		adapter-&gt;activate();
		ic-&gt;waitForShutdown();
	} catch (const Ice::Exception&amp; e) {
			cerr &lt;&lt; e &lt;&lt; endl;
		status = 1;
	} catch (const char* msg) {
		cerr &lt;&lt; msg &lt;&lt; endl;
		status = 1;
	}
	if (ic) {
		try {
			ic-&gt;destroy();
		} catch (const Ice::Exception&amp; e) {
			cerr &lt;&lt; e &lt;&lt; endl;
			status = 1;
		}
	}
	return status;
}
</PRE>
<P>以VS2003的配置为例 </P>
<DIV class=orderedlist>
<OL type=a>
<LI>
<P>把ice的include加入VC7.1的引用文件目录,把ice的lib目录加入VC7.1的库文件目录。然后再把安装目录下的bin文件夹添加到系统的环境变量Path中，最后，把bin文件夹下的所有DLL文件都Copy到Windows安装目录下的System32文件夹下（win98下是System文件夹？）（当然，DLL文件的问题也可以通过修改环境变量来解决，不过是那个变量呢？Who can tell me?） </P>
<LI>
<P>新建一个C＋＋的Win32的命令台控制程序，并且设置为空项目， 把server.cpp, printer.cpp和printer.h加入这个项目（printer.cpp和printer.h放在项目的目录的外一层目录） </P>
<LI>
<P>项目－》属性－》C/C++ -》代码生成－》运行时库－》/MD(realse版)或/MDd(debug版） </P>
<P>项目－》配置属性-》C/C++-》语言-》启用运行时类型信息/GR 开启 </P>
<P>设置：项目－》属性－》链接器－》输入－》加入iced.lib iceutild.lib，此处一定要把realse库和debug库分清, debug库后有个d </P>
<LI>
<P>修改printer.cpp中的#include &lt;printer.h&gt;为#include "printer.h" </P>
<LI>
<P>OK,编译</P></LI></OL></DIV>
<P></P>
<LI>
<P>写客户端，并编译它</P>
<P><B>文件client.cpp.&nbsp;</B></P><PRE class=programlisting>#include &lt;Ice/Ice.h&gt;
#include "..\print.h"
using namespace std;
using namespace Demo;
int main(int argc, char* argv[])
{
	int status = 0;
	Ice::CommunicatorPtr ic;
	try {
		ic = Ice::initialize(argc, argv);
		Ice::ObjectPrx base = ic-&gt;stringToProxy(
			"SimplePrinter:default -p 10000");
		PrinterPrx printer = PrinterPrx::checkedCast(base);
		if (!printer)
			throw "Invalid proxy";
		printer-&gt;printString("Hello World!");
	} catch (const Ice::Exception&amp; ex) {
		cerr &lt;&lt; ex &lt;&lt; endl;
		status = 1;
	} catch (const char* msg) {
		cerr &lt;&lt; msg &lt;&lt; endl;
		status = 1;
	}
	if (ic)
		ic-&gt;destroy();
	return status;
}
</PRE>
<P>添加一个新项目到当前解决方案，按照上面的方法，对client再一次进行设置。</P>
<P>在解决方案管理器的解决方案上点击右键，选择批生成Debug版本，然到用资源管理器到两个解决方案的目录下的Debug文件夹中执行生产的可执行文件。先运行server.exe, 然后运行client.exe, 哈哈, 是不是在server.exe的窗口里出现了Hello World!（运行一次client.exe，出现一条）</P></LI></OL></DIV>
<P>&nbsp;</P>
<P>文章源地址:http://enjoylanguage.sourceforge.net/%5Bxhtml_chunk_sourceForge%5D/ch02.html</P><img src ="http://www.cppblog.com/klsmlzm/aggbug/1710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/klsmlzm/" target="_blank">牵牛散步</a> 2005-12-13 11:56 <a href="http://www.cppblog.com/klsmlzm/archive/2005/12/13/1710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>