﻿<?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++博客-&lt;B&gt;&lt;font face="Arial" size="6" color="#FF8000"&gt;✽✽✽七楼的阳光✽✽✽&lt;/font&gt; &lt;/B&gt;-随笔分类-编程技术</title><link>http://www.cppblog.com/guangping/category/11052.html</link><description>&lt;font face="Arial" size="4" color="#FF8000"&gt;－－－宁静致远，超然世外。&lt;/font&gt; </description><language>zh-cn</language><lastBuildDate>Tue, 30 Jun 2009 19:30:23 GMT</lastBuildDate><pubDate>Tue, 30 Jun 2009 19:30:23 GMT</pubDate><ttl>60</ttl><item><title>理解循环冗余码CRC</title><link>http://www.cppblog.com/guangping/archive/2008/08/04/57980.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Mon, 04 Aug 2008 08:57:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2008/08/04/57980.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/57980.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2008/08/04/57980.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/57980.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/57980.html</trackback:ping><description><![CDATA[奇偶校验码作为一种检错码虽然简单,但是漏检率太高。在计算机网络和数据通信中用E得最广泛的检错码,是一种漏检率低得多也便于实现的循环冗余码CRC (Cyclic Redundancy .Code),CRC码又称为多项式码。<br />    任何一个由二进制数位串组成的代码,都可以惟一地与一个只含有0和1两个系数的多项式建立一一对应的关系。例如,代码1010111对应的多项式为X<sub>6</sub>+X<sub>4</sub>+X<sub>2</sub>+X+1,同样.多项式X<sub>5</sub>+X<sub>3</sub>+X<sub>2</sub>+X+1对应的代码为101111。<br />    CRC码在发送端编码和接收端校验时,都可以利用事先约定的生成多项式G(X)来得到。 k位要发送的信息位可对应于一个(k-1)次多项式K(X),r位冗余位则对应于一个(r-1)次多项式R(X),由k位信息位后面加上r位冗余位组成的n=k+r位码字则对应于一个(n-1)次多项式T(X)=X<sup>r</sup>·K(X)+R(X)。例如
<p><img src="http://zk.educity.cn/wljs/images/20069156244.gif" /></p><p>    由信息位产生冗余位的编码过程,就是已知K(X)求R(X)的过程。在CRC码中可以通过找到一个特定的r次多项式G (X)(其最高项Xr的系数恒为1),然后用Xr·K(X)去除以G(X),得到的余式就是R(X)。特别要强调的是,这些多项式中的"+"都是模2加(也即异或运算);此外,这里的除法用的也是模2除法,即除法过程中用到的减法是模2减法,它和模2加法的运算规则一样,都是异或运算,这是一种不考虑加法进位和减法借位的运算,即</p><p>    0+O=0,0+1=1,1+0=1,1+1=0<br />    0-0=0,0-1=1,1-0=1,1-1=0</p><p>    在进行基于模2运算的多项式除法时,只要部分余数首位为1,便可上商1,否则上商0。然后按模2减法求得余数,该余数不计最高位。当被除数逐位除完时,最后得到比除数少一位的余数。此余数即为冗余位,将其添加在信息位后便构成CRC码字。<br />    仍以上例中K(X)=X<sup>6</sup>+X<sup>4</sup>+X<sup>3</sup>+1为例(即信息位为1011001),若G(X)=X<sup>4</sup>+X<sup>3</sup>+1<br />(对应代码11001),取r=4,则X<sup>4</sup>·K(X)=X<sup>10</sup>+X<sup>8</sup>+X<sup>7</sup>+X<sup>4</sup>(对应代码为0110010000),其由模2除法求余式R(X)的过程所示如下:</p><p><img src="http://zk.educity.cn/wljs/images/20069159946.gif" /><br />    得到的最后余数为1010,这就是冗余位,对应R(X)=X3+X。<br />    由于R(X)是X<sup>r</sup>·K(X)除以G(X)的余式,那么下列关系式必然满足<br />    X<sup>r</sup>·K(X)=G(X)Q(X)+R(X)<br />    其中Q(X)为商式。根据模二运算规则R(X)+R(X)=0的特点,可将上式改记为</p><p>    [X<sup>r</sup>-K(X)+R(X)]/G(X)=Q(X)</p><p>    即    T(X)/G(X)=Q(X)</p><p>    由此可见,信道上发送的码字多项式T(X)=Xr-K(X)+R(X)。若传输过程无错，则接收方收到的码字也对应于此多项式,也即接收到的码字多项式能被G(X)整除。因而接收端的校验过程就是将接收到的码字多项式除以G(X)的过程。若余式为零则认为传输元差错;若余式不为零则传输有差错。</p><p><img src="http://zk.educity.cn/wljs/images/20069151070.gif" /></p><p>    例如,前述例子中若码字10110011010经传输后由于受噪声的干扰,在接收端变成为10110011100,则求余式的除法如下:<br />求得的余式不为零,相当于在码字上面半加上了差错模式00000000110。差错模式对应的多项式记为E(X),上例中E(X)=X2+X。有差错时,接收端收到的不再是T(X),而是T(X)与E(X)之模二加,即<br />    [T(X)+E(X)]/G(X)=T(X)/G(X)+E(X)/G(X)<br />若E(X)/G(X)=0,则这种差错就能检测出来;若E(X)/G(X)=0,那么由于接收到的码字多项式仍然可被G(X)整除,错误就检测不出来,也即发生了漏检。</p><p>    理论上可以证明循环冗余校验码的检错能力有以下特点:<br />    (1)可检测出所有奇数位错。<br />    (2)可检测出所有双比特的错。<br />    (3)可检测出所有小于、等于校验位长度的突发错。</p><p><clk>    CRC码是由r-K(X)除以某个选定的多项式后产生的,所以该多现式称生成多项式。一般来说,生成多项式位数越多校验能力越强。但并不是任何一个r+1位的二进制数都可以做生成多项式。<nobr oncontextmenu="return false" onmousemove="kwM(0)" id="clickeyekey0" onmouseover="kwE(event,0, this)" style="COLOR: #6600ff; BORDER-BOTTOM: #6600ff 1px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="kwC(event,0)" onmouseout="kwL(event,this)">目前</nobr>广泛使用的生成多项式主要有以下四种:</clk><br /><img src="http://zk.educity.cn/wljs/images/20069158141.gif" /></p><img src ="http://www.cppblog.com/guangping/aggbug/57980.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2008-08-04 16:57 <a href="http://www.cppblog.com/guangping/archive/2008/08/04/57980.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中的左值和右值</title><link>http://www.cppblog.com/guangping/archive/2008/04/23/47889.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Wed, 23 Apr 2008 03:40:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2008/04/23/47889.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/47889.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2008/04/23/47889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/47889.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/47889.html</trackback:ping><description><![CDATA[1.  概念
变量和文字常量都有存储区，并且有相关的类型，区别在于变量是可寻址的；
<br />
对于每个变量，都有2个值与其相关联：<br /> 1&gt;数据值，存储在某个内存地址中，也称右值（rvalue），右值是被读取的值（read value），文字常量和变量都可被用于右值。
<br /> 2&gt;地址值，即存储数据值的那块内存地址，也称左值（lvalue），文字常量不能被用作左值。
<br /><br />2 . 问题
给表达式加上括号：<br /> ++a--
<br />结果 ++(a--)
<br />这个表达式是非法的，因为前增量操作要求一个可修改的左值，而 "a--" 不是左值（即右值）<br /><br /> 3 . 前增量和后增量的区别
<br />早期的c语言教材，for循环语句通常写成：<br />for(int i=0;i&lt;10;i++)
<br />而现在多为：
<br />for(int i=0;i&lt;10;++i)
两者有区别吗？
<br />a++ 即是返回 a的值，然后变量 a 加 1，返回需要产生一个临时变量类似于
<br />{
int temp = a;
<br />   a=a+1;
<br />   return temp;  //返回右值
}
<br /><br />++a 则为：
<br />{
a=a+1;
<br />   return &amp;a;    //返回左值
}
<br />显然，前增量不需要中间变量，效率更高。  <img src ="http://www.cppblog.com/guangping/aggbug/47889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2008-04-23 11:40 <a href="http://www.cppblog.com/guangping/archive/2008/04/23/47889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>typedef用法小结</title><link>http://www.cppblog.com/guangping/archive/2008/04/08/46519.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Tue, 08 Apr 2008 08:21:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2008/04/08/46519.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/46519.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2008/04/08/46519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/46519.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/46519.html</trackback:ping><description><![CDATA[
		<font face="Courier New">
				<font size="4">这两天在看程序的时候,发现很多地方都用到typedef,在结构体定义,还有一些数组等地方都大量的用到.但是有些地方还不是很清楚,今天下午,就想好好研究一下.上网搜了一下,有不少资料.归纳一下:<br />来源一:Using typedef to Curb Miscreant Code<br />Typedef 声明有助于创建平台无关类型，甚至能隐藏复杂和难以理解的语法。不管怎样，使用 typedef 能为代码带来意想不到的好处，通过本文你可以学习用 typedef 避免缺欠，从而使代码更健壮。<br />typedef 声明，简称 typedef，为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观，意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型，从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。<br />如何创建平台无关的数据类型，隐藏笨拙且难以理解的语法?<br />使用 typedefs 为现有类型创建同义字。<br />定义易于记忆的类型名<br />　　typedef 使用最多的地方是创建易于记忆的类型名，用它来归档程序员的意图。类型出现在所声明的变量名字中，位于 ''typedef'' 关键字右边。例如：<br />typedef int size;<br />　　此声明定义了一个 int 的同义字，名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size：<br />void measure(size * psz);<br />size array[4];<br />size len = file.getlength();<br />std::vector vs;<br />　　typedef 还可以掩饰符合类型，如指针和数组。例如，你不用象下面这样重复定义有 81 个字符元素的数组：<br />char line[81];<br />char text[81];<br />定义一个 typedef，每当要用到相同类型和大小的数组时，可以这样：<br />typedef char Line[81];<br />Line text, secondline;<br />getline(text);<br />同样，可以象下面这样隐藏指针语法：<br />typedef char * pstr;<br />int mystrcmp(pstr, pstr);<br />　　这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个‘const char *'类型的参数。因此，它可能会误导人们象下面这样声明 mystrcmp()：<br />int mystrcmp(const pstr, const pstr);<br />　　这是错误的，按照顺序，‘const pstr'被解释为‘char * const'（一个指向 char 的常量指针），而不是‘const char *'（指向常量 char 的指针）。这个问题很容易解决：<br />typedef const char * cpstr;<br />int mystrcmp(cpstr, cpstr); // 现在是正确的<br />记住：不管什么时候，只要为指针声明 typedef，那么都要在最终的 typedef 名称中加一个 const，以使得该指针本身是常量，而不是对象。<br />代码简化<br />　　上面讨论的 typedef 行为有点像 #define 宏，用其实际类型替代同义字。不同点是 typedef 在编译时被解释，因此让编译器来应付超越预处理器能力的文本替换。例如：<br />typedef int (*PF) (const char *, const char *);<br />　　这个声明引入了 PF 类型作为函数指针的同义字，该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明，那么上述这个 typedef 是不可或缺的：<br />PF Register(PF pf);<br />　　Register() 的参数是一个 PF 类型的回调函数，返回某个函数的地址，其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef，我们是如何实现这个声明的：<br />int (*Register (int (*pf)(const char *, const char *)))<br />(const char *, const char *);<br />　　很少有程序员理解它是什么意思，更不用说这种费解的代码所带来的出错风险了。显然，这里使用 typedef 不是一种特权，而是一种必需。持怀疑态度的人可能会问："OK，有人还会写这样的代码吗？"，快速浏览一下揭示 signal()函数的头文件 ，一个有同样接口的函数。<br />typedef 和存储类关键字（storage class specifier）<br />　　这种说法是不是有点令人惊讶，typedef 就像 auto，extern，mutable，static，和 register 一样，是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性；它只是说在语句构成上，typedef 声明看起来象 static，extern 等类型的变量声明。下面将带到第二个陷阱：<br />typedef register int FAST_COUNTER; // 错误<br />　　编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置，在 typedef 声明中不能用 register（或任何其它存储类关键字）。<br />促进跨平台开发<br />　　typedef 有另外一个重要的用途，那就是定义机器无关的类型，例如，你可以定义一个叫 REAL 的浮点类型，在目标机器上它可以i获得最高的精度：<br />typedef long double REAL;<br />在不支持 long double 的机器上，该 typedef 看起来会是下面这样：<br />typedef double REAL;<br />并且，在连 double 都不支持的机器上，该 typedef 看起来会是这样：、<br />typedef float REAL;<br />　 　你不用对源代码做任何修改，便可以在每一种平台上编译这个使用 REAL 类型的应用程序。唯一要改的是 typedef 本身。在大多数情况下，甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。不是吗? 标准库广泛地使用 typedef 来创建这样的平台无关类型：size_t，ptrdiff 和 fpos_t 就是其中的例子。此外，象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的，难以理解的模板特化语法，例如：basic_string，allocator&gt; 和 basic_ofstream&gt;。<br />作者简介<br />　　Danny Kalev 是一名通过认证的系统分析师，专攻 C++ 和形式语言理论的软件工程师。1997 年到 2000 年期间，他是 C++ 标准委员会成员。最近他以优异成绩完成了他在普通语言学研究方面的硕士论文。业余时间他喜欢听古典音乐，阅读维多利亚时期的文学作品，研究 Hittite、Basque 和 Irish Gaelic 这样的自然语言。其它兴趣包括考古和地理。Danny 时常到一些 C++ 论坛并定期为不同的 C++ 网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。<br />来源二：(http://www.ccfans.net/bbs/dispbbs.asp?boardid=30&amp;;id=4455)<br />C语言中typedef用法<br />1. 基本解释<br />　　typedef为C语言的关键字，作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型（int,char等）和自定义的数据类型（struct等）。<br />　　在编程中使用typedef目的一般有两个，一个是给变量一个易记且意义明确的新名字，另一个是简化一些比较复杂的类型声明。<br />　　至于typedef有什么微妙之处，请你接着看下面对几个问题的具体阐述。<br />　2. typedef &amp; 结构的问题<br />　　当用下面的代码定义一个结构时，编译器报了一个错误，为什么呢？莫非C语言不允许在结构中包含指向它自己的指针吗？请你先猜想一下，然后看下文说明：<br />typedef struct tagNode<br />{<br />　char *pItem;<br />　pNode pNext;<br />} *pNode;<br />　　答案与分析：<br />　　1、typedef的最简单使用<br />typedef long byte_4;<br />　　给已知数据类型long起个新名字，叫byte_4。<br />　　2、 typedef与结构结合使用<br />typedef struct tagMyStruct<br />{<br />　int iNum;<br />　long lLength;<br />} MyStruct;<br />　　这语句实际上完成两个操作：<br />　　1) 定义一个新的结构类型<br />struct tagMyStruct<br />{<br />　int iNum;<br />　long lLength;<br />};<br />　　分析：tagMyStruct称为“tag”，即“标签”，实际上是一个临时名字，struct 关键字和tagMyStruct一起，构成了这个结构类型，不论是否有typedef，这个结构都存在。<br />　　我们可以用struct tagMyStruct varName来定义变量，但要注意，使用tagMyStruct varName来定义变量是不对的，因为struct 和tagMyStruct合在一起才能表示一个结构类型。<br />　　2) typedef为这个新的结构起了一个名字，叫MyStruct。<br />typedef struct tagMyStruct MyStruct;<br />　　因此，MyStruct实际上相当于struct tagMyStruct，我们可以使用MyStruct varName来定义变量。<br />　　答案与分析<br />　　C语言当然允许在结构中包含指向它自己的指针，我们可以在建立链表等数据结构的实现上看到无数这样的例子，上述代码的根本问题在于typedef的应用。<br />　　根据我们上面的阐述可以知道：新结构建立的过程中遇到了pNext域的声明，类型是pNode，要知道pNode表示的是类型的新名字，那么在类型本身还没有建立完成的时候，这个类型的新名字也还不存在，也就是说这个时候编译器根本不认识pNode。<br />　　解决这个问题的方法有多种：<br />　　1)、<br />typedef struct tagNode<br />{<br />　char *pItem;<br />　struct tagNode *pNext;<br />} *pNode;<br />　　2)、<br />typedef struct tagNode *pNode;<br />struct tagNode<br />{<br />　char *pItem;<br />　pNode pNext;<br />};<br />　　注意：在这个例子中，你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。<br />　　3)、规范做法：<br />struct tagNode<br />{<br />　char *pItem;<br />　struct tagNode *pNext;<br />};<br />typedef struct tagNode *pNode;<br />　3. typedef &amp; #define的问题<br />　　有下面两种定义pStr数据类型的方法，两者有什么不同？哪一种更好一点？<br />typedef char *pStr;<br />#define pStr char *;<br />　　答案与分析：<br />　　通常讲，typedef要比#define要好，特别是在有指针的场合。请看例子：<br />typedef char *pStr1;<br />#define pStr2 char *;<br />pStr1 s1, s2;<br />pStr2 s3, s4;<br />　　在上述的变量定义中，s1、s2、s3都被定义为char *，而s4则定义成了char，不是我们所预期的指针变量，根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。<br />　　#define用法例子：<br />#define f(x) x*x<br />main( )<br />{<br />　int a=6，b=2，c；<br />　c=f(a) / f(b)；<br />　printf("%d \\n"，c)；<br />}<br />　　以下程序的输出结果是: 36。<br />　　因为如此原因，在许多C语言编程规范中提到使用#define定义时，如果定义中包含表达式，必须使用括号，则上述定义应该如下定义才对：<br />#define f(x) (x*x)<br />　　当然，如果你使用typedef就没有这样的问题。<br />　　4. typedef &amp; #define的另一例<br />　　下面的代码中编译器会报一个错误，你知道是哪个语句错了吗？<br />typedef char * pStr;<br />char string[4] = "abc";<br />const char *p1 = string;<br />const pStr p2 = string;<br />p1++;<br />p2++;<br />　　答案与分析：<br />　　是p2++出错了。这个问题再一次提醒我们：typedef和#define不同，它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别，都是对变量进行只读限制，只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此，const pStr p2的含义是：限定数据类型为char *的变量p2为只读，因此p2++错误。<br />　　#define与typedef引申谈<br />　　1) #define宏定义有一个特别的长处：可以使用 #ifdef ,#ifndef等来进行逻辑判断，还可以使用#undef来取消定义。<br />　　2) typedef也有一个特别的长处：它符合范围规则，使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内（取决于此变量定义的位置），而宏定义则没有这种特性。<br />　　5. typedef &amp; 复杂的变量声明<br />　　在编程实践中，尤其是看别人代码的时候，常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值，比如：<br />　　下面是三个变量的声明，我想使用typdef分别给它们定义一个别名，请问该如何做？<br />&gt;1：int *(*a[5])(int, char*);<br />&gt;2：void (*b[10]) (void (*)());<br />&gt;3. doube(*)() (*pa)[9];<br />　　答案与分析：<br />　　对复杂变量建立一个类型别名的方法很简单，你只要在传统的变量声明表达式里用类型名替代变量名，然后把关键字typedef加在该语句的开头就行了。<br />&gt;1：int *(*a[5])(int, char*);<br />//pFun是我们建的一个类型别名<br />typedef int *(*pFun)(int, char*);<br />//使用定义的新类型来声明对象，等价于int* (*a[5])(int, char*);<br />pFun a[5];<br />&gt;2：void (*b[10]) (void (*)());<br />//首先为上面表达式蓝色部分声明一个新类型<br />typedef void (*pFunParam)();<br />//整体声明一个新类型<br />typedef void (*pFun)(pFunParam);<br />//使用定义的新类型来声明对象，等价于void (*b[10]) (void (*)());<br />pFun b[10];<br />&gt;3. doube(*)() (*pa)[9];<br />//首先为上面表达式蓝色部分声明一个新类型<br />typedef double(*pFun)();<br />//整体声明一个新类型<br />typedef pFun (*pFunParam)[9];<br />//使用定义的新类型来声明对象，等价于doube(*)() (*pa)[9];<br />pFunParam pa;</font>
		</font>
		<br />
<img src ="http://www.cppblog.com/guangping/aggbug/46519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2008-04-08 16:21 <a href="http://www.cppblog.com/guangping/archive/2008/04/08/46519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows下用vim实现qt代码的自动补全功能</title><link>http://www.cppblog.com/guangping/archive/2008/02/18/42917.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Mon, 18 Feb 2008 15:29:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2008/02/18/42917.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/42917.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2008/02/18/42917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/42917.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/42917.html</trackback:ping><description><![CDATA[
		<span class="tpc_content">1.安装vim.<br />2.下载ctags for win32并解压到c:\ctags\目录下;<br />3.将c:\ctags加入windows的path环境变量中;<br />4.下载omnicppcomplete将解压到vim安装目录的vimfiles目录下;<br />5.转到qt的include目录下执行ctags -R --c++-kinds=+p --fields=+iaS --extra=+q;命令完成后会在该目录下<br />生成一个tags文件，它是omnicppcomplete和vim用来作命令补全的数据库。<br />6.在qt的src目录下再执行一遍上述命令;<br />7.编辑vim安装目录下的_vimrc文件，将下述两行加入其中<br />set tags+=c:\Qt\4.3.3\include\tags<br />set tags+=c:\Qt\4.3.3\src\tag<br />其中c:\Qt\4.3.3\是我机器上qt 的安装目录，根据你的情况作出调整。<br />8.到你的工程目录下执行5步中的命令;<br />9.用vim打开一个cpp文件试一下吧，哈哈;<br /><br /></span>
<img src ="http://www.cppblog.com/guangping/aggbug/42917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2008-02-18 23:29 <a href="http://www.cppblog.com/guangping/archive/2008/02/18/42917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++ 内存管理 Heap vs Stack</title><link>http://www.cppblog.com/guangping/archive/2007/08/01/29131.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Wed, 01 Aug 2007 03:24:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/08/01/29131.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/29131.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/08/01/29131.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/29131.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/29131.html</trackback:ping><description><![CDATA[
		<div class="postTitle">
				<br />
		</div>一、预备知识—程序的内存分配 <br />一个由c/C++编译的程序占用的内存分为以下几个部分 <br />1、栈区（stack）— 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。 <br />2、堆区（heap） — 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。 <br />3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 <br />4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 <br />5、程序代码区—存放函数体的二进制代码。 <br /><br />二、例子程序 <br />这是一个前辈写的，非常详细 <br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="../../Images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">main.cpp </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> a </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">; 全局初始化区 <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">p1; 全局未初始化区 <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />main() <br /><img id="Codehighlighter1_58_337_Open_Image" onclick="this.style.display='none'; Codehighlighter1_58_337_Open_Text.style.display='none'; Codehighlighter1_58_337_Closed_Image.style.display='inline'; Codehighlighter1_58_337_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_58_337_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_58_337_Closed_Text.style.display='none'; Codehighlighter1_58_337_Open_Image.style.display='inline'; Codehighlighter1_58_337_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_58_337_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_58_337_Open_Text"><span style="color: rgb(0, 0, 0);">{ <br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> b;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 栈 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> s[] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">abc</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">; </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">栈 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">p2; </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">栈 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">p3 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">123456</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">; </span><span style="color: rgb(0, 0, 0);">123456</span><span style="color: rgb(0, 0, 0);">\</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;//在常量区，p3在栈上。 </span><span style="color: rgb(0, 0, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> c </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">； </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">全局（静态）初始化区 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">p1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)malloc(</span><span style="color: rgb(0, 0, 0);">10</span><span style="color: rgb(0, 0, 0);">); <br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />p2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)malloc(</span><span style="color: rgb(0, 0, 0);">20</span><span style="color: rgb(0, 0, 0);">); <br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">分配得来得10和20字节的区域就在堆区。 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">strcpy(p1, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">123456</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">); </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">123456\0放在常量区，编译器可能会将它与p3所指向的"123456"优化成一个地方。 </span><span style="color: rgb(0, 128, 0);"><br /><img src="../../Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">}</span></span><span style="color: rgb(0, 0, 0);"><br /><img src="../../Images/OutliningIndicators/None.gif" align="top" /></span></div><br />三、堆和栈的理论知识 <br />3.1申请方式 <br />stack: <br />由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 <br />heap: <br />需要程序员自己申请，并指明大小，在c中malloc函数 <br />如p1 = (char *)malloc(10); <br />在C++中用new运算符 <br />如p2 = (char *)malloc(10); <br />但是注意p1、p2本身是在栈中的。 <br />3.2 申请后系统的响应 <br />栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。 <br />堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时， <br />会
遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内
存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的堆结点的大小不一定正好等于申请的大
小，系统会自动的将多余的那部分重新放入空闲链表中。 <br />3.3申请大小的限制 <br />栈：在Windows下,栈是向低地址扩展的数据结构，
是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在 WINDOWS下，栈的大小是2M（也有的说是1M，总之是一
个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。 <br />堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。 <br />3.4申请效率的比较： <br />栈由系统自动分配，速度较快。但程序员是无法控制的。 <br />堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便. <br />另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活 <br />3.5堆和栈中的存储内容 <br />栈： 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。 <br />当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。 <br />堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 <br />3.6存取效率的比较 <br /><br />char s1[] = "aaaaaaaaaaaaaaa"; <br />char *s2 = "bbbbbbbbbbbbbbbbb"; <br />aaaaaaaaaaa是在运行时刻赋值的； <br />而bbbbbbbbbbb是在编译时就确定的； <br />但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。 <br />比如： <br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">stdio.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">; <br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main() <br />{ <br /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> a </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">; <br /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> c[] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">1234567890</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">; <br /></span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">p </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">1234567890</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">; <br />a </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> c[</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">]; <br />a </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> p[</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">]; <br /></span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">; <br />} </span></div><br />对应的汇编代码 <br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="../../Images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);">10: a = c[1]; <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />0040106A 88 4D FC mov byte ptr [ebp-4],cl <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />11: a = p[1]; <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />00401070 8A 42 01 mov al,byte ptr [edx+1] <br /><img src="../../Images/OutliningIndicators/None.gif" align="top" />00401073 88 45 FC mov byte ptr [ebp-4],al </span></div><br />第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。 <br /><br /><br />3.7小结： <br />堆和栈的区别可以用如下的比喻来看出： <br />使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。 <br />使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。 <br /><br />堆和栈的区别主要分： <br />操作系统方面的堆和栈，如上面说的那些，不多说了。 <br />还有就是数据结构方面的堆和栈，这些都是不同的概念。这里的堆实际上指的就是（满足堆性质的）优先队列的一种数据结构，第1个元素有最高的优先权；栈实际上就是满足先进后出的性质的数学或数据结构。 <br />虽然堆栈，堆栈的说法是连起来叫，但是他们还是有很大区别的，连着叫只是由于历史的原因<img src ="http://www.cppblog.com/guangping/aggbug/29131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-08-01 11:24 <a href="http://www.cppblog.com/guangping/archive/2007/08/01/29131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OCI经典参考文档（转载）</title><link>http://www.cppblog.com/guangping/archive/2007/07/06/27605.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Fri, 06 Jul 2007 07:44:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/07/06/27605.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/27605.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/07/06/27605.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/27605.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/27605.html</trackback:ping><description><![CDATA[		一． Oracle oci工具包安装： <br />$ORACLE_HOME\BIN:执行文件和help文件 <br />$ORACLE_HOME\OCI\INCLUDE:头文件 <br />$ORACLE_HOME\OCI\LIB\BC:  for Borlanf C++的OCI库 <br />$ORACLE_HOME\OCI\LIB\MSVC:  for MS Visual C++的OCI库 <br /><br />如果是unix下，对于ORACLE8i，则OCI库在$ORACLE_HOME/lib下,如果是9i,则在$ORACLE_HOME/lib32下，库文件名一般为libclntsh.so <br />1． 创建OCI环境即创建和初始化OCI工作环境，其他的OCI函数需要OCI环境才能执行。 <br />2． 需要申请的句柄类型： <br />OCI环境句柄： OCI_HTYPE_ENV—它定义所有OCI函数的环境调用环境，是其他句柄的父句柄。(由OCIEnvInit或OCIEnvCreate生成) <br /> 错误句柄：OCI_HTYPE_ERROR—作为一些OCI函数的参数，用来记录这些OCI函数操作过程中所产生的错误，当有错误发生时，可用COIErrorGet()来读取错误句柄 中记录的错误信息。 <br />服务器环境句柄：OCI_HTYPE_SVCCTX—定义OCI调用的服务器操作环境，它包含服务器、用户会话和事务三种句柄。 <br />服务器句柄：OCI_HTYPE_SERVER—标识数据源，它转换为与服务器的物理连接。 <br />用户会话句柄：OCI_HTYPE_SESSION—定义用户角色和权限及OCI调用的执行环境。 <br />事务句柄：OCI_HTYPE_TRANS—定义执行SQL操作的事务环境，事务环境中包含用户的会话状态信息。 <br />语句句柄：OCI_HTYPE_STMT—是一个标识SQL语句或PL/SQL块，以及其相关属性的环境。 <br />Bind/Define句柄：属于语句句柄的子句柄，由OCI库隐式自动生成。用户不需要自己再申请，OCI输入变量存储在bind 句柄中，输出变量存储在定义句柄中 <br /><br />　3． 句柄属性包括： <br />服务器环境句柄属性：(OCI_HTYPE_SVCCTX) <br /> OCI_ATTR_SERVER—设置/读取服务环境的服务器环境属性 <br /> OCI_ATTR_SESSION—设置/读取服务环境的会话认证环境属性 <br />               OCI_ATTR_TRANS—设置/读取服务环境的事务环境属性 <br />用户会话句柄属性：(OCI_HTYPE_SESSION) <br />OCI_ATTR_USERNAME—设置会话认证所使用的用户名 <br />  OCI_ATTR_PASSWORD—设置会话认证所使用的用户口令 <br />服务器句柄：(OCI_HTYPE_SEVER) <br />OCI_ATTR_NOBLOCKING_MODE—设置/读取服务器连接：=TRUE时服务器连接设置为非阻塞方式 <br />语句句柄：(OCI_HTYPE_STMT)  <br />OCI_ATTR_ROW_COUNT—只读，为当前已处理的行数，其default=1 <br />OCI_ATTR_STMT_TYPE—读取当前SQL语句的类型： <br />Eg : OCI_STMT_BEGIN <br />       OCI_STMT_SELECT   OCI_STMT_INSERT     <br />OCI_STMT_UPDATE  OCI_STMT_DELETE <br />                   OCI_ATTR_PARAM_COUNT—返回语句选择列表中的列数 <br />4． 关于输出变量定义：如果在语句执行前就知道select语句的选择列表结构，则定义输出操作可在调用 OCISTMTExecute前进行，如果查询语句的参数为用户动态输入的，则必须在执行后定义。 <br />5． OCI函数返回值： <br />OCI_SUCCESS –函数执行成功 (=0) <br />OCI_SUCCESS_WITH_INFO –执行成功，但有诊断消息返回，可能是警告信息 <br />OCI_NO_DATA—函数执行完成，但没有其他数据 <br />OCI_ERROR—函数执行错误 <br />OCI_INVALID_HANDLE—传递给函数的参数为无效句柄，或传回的句柄无效 <br />OCI_NEED_DATA—需要应用程序提供运行时刻的数据 <br />OCI_CONTINUE—回调函数返回代码，说明回调函数需要OCI库恢复其正常的处理操作 <br />OCI_STILL_EXECUTING—服务环境建立在非阻塞模式，OCI函数调用正在执行中。 <br />6．
OCI连接有二种方式：Blocking(阻塞方式)和non_Blocking(非阻塞方式)，阻塞方式就是当调用 OCI操作时，必须等到此OCI操
作完成后服务器才返回客户端相应的信息，不管是成功还是失败。非阻塞方式是当客户端提交OCI操作给服务器后，服务器立即返回
OCI_STILL_EXECUTING信息，而并不等待服务端的操作完成。 <br /><br /><br />  对于non-blocking方式，应用程序若收到一个OCI函数的返回值为 OCI_STILL_EXECUTING时必须再次对每一个OCI函数的返回值进行判断，判断其成功与否。 <br />  可通过设置服务器属性为OCI_ATTR_NONBLOCKING_MODE来实现。系统默认方式为阻塞模式. <br />7． OCI函数设置的模式有： <br />  OCI_DEFUALT:使用OCI默认的环境 <br />  OCI_THREADED：线程环境下使用OCI <br />  OCI_OBJECT：对象模式 <br />  OCI_SHARED：共享模式 <br />  OCI_EVENTS <br />  OCI_NO_UCB <br />  OCI_ENV_NO_MUTEX：非互斥访问模式 <br />  其中模式可以用逻辑运算符进行迭加，将函数设置成多多种模式：如mode=OCI_SHREADED| OCI_OBJECT <br /><br />8． 当应用进程与服务器断开连接时，程序没有使用OCITransCommit()进行事务的提交，则所有活动的事务会自动回滚。  <br />9． OCI重定义数据类型 <br />     typedef unsigned char  ub1;     <br />typedef   signed char  sb1; <br />typedef unsigned short    ub2;   <br />typedef   signed short    sb2; <br />typedef unsigned int  ub4;    <br />typedef   signed int  sb4;   <br />typedef         ub4      duword;     <br />typedef         sb4      dsword;     <br />typedef         dsword   dword; <br /><br />10． 在SQL语句准备后，可以用OCIAttrSet(0设置该语句的类型属性OCI_ATTR_STMT_TYPE，以后可读取语句属性，根据属性分别进行处理。 <br />11． 批量绑定输入和定义输出参数：将数据存入一个静态数据组中。一次执行可以提交或读取多行记录值。 <br />12． 结合占位符和指示器变量： <br />占
位符：在程序中，一些SQL语句需要在程序运行时才能确定它的语句数据，在设计时可用一个占位符来代替，当程序运行时，在它准备好语句后，必须为每个占位
符指定一个变量，即将占位符与程序变量地址结合，执行时，Oracle就从这些变量中读取数据，并将它们与SQL语句一起传递给Oracle服务器执行。
OCI结合占位符时，它将占位符与程序变量关联起来，并同时要指出程序变量的数据类型和数据长度。 <br />如：select * from test where name=:p1 and age&gt;:p2  <br />：p1和：p2为占位符 <br /><br />指
示器变量：由于在Oracle中，列值可以为NULL，但在C语言中没有NULL值，为了能使OCI程序表达NULL列值，OCI函数允许程序为所执行语
句中的结合变量同时关联一个指示符变量或指示符变量数组，以说明所结合的占位符是否为NULL或所读取的列值是否为NULL，以及所读取的列值是否被截
取。 <br />除SQLT＿NTY（SQL Named DataType）外，指示符变量或指示符变量数组的数据类型为sb2,其值说明： <br />作为输入变量时：（如insert ,update语句中） <br />　=-1：OCI程序将NULL赋给Oracle表的列，忽略占位符结合的程序变量值 <br />&gt;=0：应用程序将程序变量值赋给指定列 <br />作为输出变量时：（如select语句中） <br /> ＝-2：所读取的列数据长度大于程序变量的长度，则被截取。 <br /> =-1：所读取的值为NULL,输出变量的值不会被改变。 <br />=0：数据被完整读入到指定的程序变量中 <br />＞0：所读取的列数据长度大于程序变量的长度，则被截取，指示符变量值为所读取数据被截取前的实际长度 <br />三． OCI函数说明 <br />注：红色为输入参数   蓝色为输出参数  ,否则为输入/出参数 <br /><br /> 示例以下面结构作为说明 <br />   sword     swResult; <br />OCIBind*  hBind; <br />  OCIDefine*  hDefine; <br />OCIStmt      *stmtp <br />OCIError     *errhp； <br />OCIStmt       *stmtp <br />OCISvcCtx  * svchp <br />OCIEnv * envhpp; <br />OCISession * usrhp; <br />sb2 sb2aInd[30]; //指示器变量，用于取可能存在空值的字段 <br />Typedef strcut  <br />{ <br />char tname[40]; <br />int age; <br />} t_std; <br />typedef struct <br />{ <br />sb2     sb2_tname[100]; <br />        sb2     sb2_age[100]; <br />} stdInd_T;  //指示器数组 <br />typedef struct <br />{ <br />ub2     ub2_tname[100]; <br />       ub2     ub2_age[100]; <br />} stdLen_T; //字段长度 <br /><br />t_std tstd[100];  //数组变量，用于批量操作 <br />stdInd_T tstdInd; <br />stdLen_T tstdLen; <br />stdLen_T tstdRet; <br /><br /> t_std std; <br /><br />各函数数明 <br />1．创建OCI环境 <br />sword OCIEnvCreate(   <br />OCIEnv **envhpp,  //OCI环境句柄指针 <br />ub4 mode, //初始化模式：OCI_DEFAULT/OCI_THREADED 等 <br />CONST dvoid *ctxp, <br />CONST dvoid *(*malicfp)(dvoid *ctxp,size_t size), <br />CONST dvoid *(ralocfp)(dvoid *ctxp,dvoid *memptr,size_t newsize), <br />CONST void *(*mfreefp)(dvoid *ctxp,dvoid *memptr), <br />Size_t xstramemsz, <br />Dvoid **usrmempp <br />) <br />eg : <br />  swResult = OCIEnvCreate(&amp;envhpp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL); <br /><br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO)  <br />return FALSE; <br /><br />sword OCIInitialize ( <br />  ub4           mode, <br />                       CONST dvoid   *ctxp,  <br />                       CONST dvoid   *(*malocfp)   (/* dvoid *ctxp,  size_t size _*/), <br />                      CONST dvoid   *(*ralocfp) (/*_ dvoid *ctxp, dvoid *memptr, size_t newsize _*/), <br />                       CONST void    (*mfreefp) (/*_ dvoid *ctxp, dvoid *memptr _*/) <br />); <br /><br />sword OCIEnvInit (  <br />OCIEnv    **envhpp, <br />                   ub4       mode, <br />                    size_t    xtramemsz, <br />                   dvoid     **usrmempp <br /> ); <br />注： <br /> 在8i以后，可用OCIEnvCreate一个函数就可以初始化环境了，相当于OCIInitialize+ OCIEnvInit <br /><br />2．申请/释放句柄 <br />   sword OCIHandleAlloc( <br />CONST dvoid *parenth,  //新申请句柄的父句柄，一般为OCI环境句柄 <br />Dvoid **hndlpp,   //申请的新句柄  <br />Ub4 type, type,  //句柄类型 <br />Size_t xtramem_sz,   //申请的内存数 <br />Dvoid **usrmempp  //申请到的内存块指针 <br />) <br />注： <br />  一般需要申请的句柄有： <br />               服务器句柄OCIServer, 句柄类型OCI_HTYPE_SERVER <br />错误句柄OCIError，用于捕获OCI错误信息, 句柄类型OCI_HTYPE_ERROR <br />事务句柄OCISession, 句柄类型OCI_HTYPE_SESSION <br />上下文句柄OCISvcCtx, 句柄类型OCI_HTYPE_SVCCTX <br />SQL语句句柄OCIStmt, 句柄类型OCI_HTYPE_STMT <br />eg: 申请一个错误句柄OCIError <br />swResult = OCIHandleAlloc(envhpp, (dvoid *)&amp; errhp, OCI_HTYPE_ERROR, 0, NULL); <br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO) <br />{ <br /><br />return FALSE; <br />} <br /><br />释放句柄 <br />  sword OCIHandleFree( <br />dvoid *hndlp,  //要释放的句柄 <br />ub4 type   //句柄类型 <br />) <br /><br />eg: <br /> OCIHandleFree(stmtp, OCI_HTYPE_STMT) <br />3．读取/设置句柄属性 <br />  sword OCIAttrSet( <br />dvoid *trgthndlp,  //需设置的句柄名 <br />ub4  trghndltyp, //句柄类型 <br />dvoid *attributep, //设置的属性名 <br />ub4 size, //属性值长度 <br />ub4 attrtype,     //属性类型 <br />OCIError *errhp   //错误句柄 <br />) <br />注：一般要设置的属性有： <br />  服务器实例： <br />句柄类型OCI_HTYPE_SVCCTX，属性类型OCI_ATTR_SERVER <br />        连接数据的用户名： <br />   句柄类型OCI_HTYPE_SESSION，属性类型OCI_ATTR_USERNAME <br />用户密码 <br />     句柄类型OCI_HTYPE_SESSION，属性类型OCI_ATTR_PASSWORD <br />事务：   <br />   句柄类型OCI_HTYPE_SVCCTX，属性类型OCI_ATTR_SESSION <br /><br />eg:设置用户名和密码 <br />char username[20],passwd[20]; <br />  strcpy(username,”tiger”) <br />strcpy(passwd,”cotton”) <br />swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION,  (text*) username, strlen(username),  <br />OCI_ATTR_USERNAME, errhp); <br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO) <br />return FALSE; <br /><br />swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION,    (text*) passwd, strlen(passwd),  <br />OCI_ATTR_PASSWORD, errhp); <br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO) <br />return FALSE; <br /><br /><br />sword OCIAttrGet( <br />dvoid *trgthndlp,  //需读取的句柄名 <br />ub4  trghndltyp, //句柄类型 <br />dvoid *attributep, //读取的属性名 <br />ub4 *sizep, //属性值长度 <br />ub4 attrtype,     //属性类型 <br />OCIError *errhp   //错误句柄 <br />) <br /><br />4．连接/断开服务器 <br />   多用户方式连接： <br />  sword  OCIServerAttach( <br />OCIServer     *srvhp,//未初始化的服务器句柄 <br />                      OCIError      *errhp, <br />                          CONST text    *dblink,//服务器SID <br />                         sb4           dblink_len, <br />                        ub4           mode //=OCI_DEFAULT,系统环境将设为阻塞方式 <br />); <br /><br />   sword OCIServerDetach ( <br />OCIServer   *srvhp, <br />                 OCIError    *errhp, <br />                         ub4         mode //OCI_DEFAULT <br />);  <br />单用户方式连接： <br />   sword OCILogon ( <br />OCIEnv          *envhp, <br />                    OCIError        *errhp, <br />                   OCISvcCtx       **svchp, <br />                  CONST text      *username, <br />                  ub4             uname_len, <br />                   CONST text      *password, <br />                   ub4             passwd_len, <br />                   CONST text      *dbname, <br />                   ub4             dbname_len  <br />); <br /><br />sword OCILogoff (  <br />OCISvcCtx      *svchp <br />                  OCIError       *errhp  <br />); <br /><br />5．开始/结束一个会话 <br />先认证用户再建立一个会话连接 <br />   sword OCISessionBegin (  <br />OCISvcCtx     *svchp,  //服务环境句柄 <br />                      OCIError      *errhp, <br />                  OCISession    *usrhp,   //用户会话句柄 <br />                         ub4           credt,    //认证类型 <br />                         ub4           mode   //操作模式 <br />); <br /><br />          *认证类型： <br />OCI_CRED_RDBMS:用数据库用户名和密码进行认证，则先要设置OCI_ATTR_USERNAME和OCI_ATTR_PASSWORD属性 <br />OCI_CRED_EXT:外部认证，不需要设置用户和密码 <br />OCI_DEFAULT：用户会话环境只能被指定的服务器环境句柄所设置 <br />OCI_SYSDBA：用户要具有sysdba权限 <br />OCI_SYSOPER：用户要具有sysoper权限 <br /><br /><br />Eg: <br />swResult = OCISessionBegin(svchp, errh,usrhp, OCI_CRED_RDBMS, OCI_DEFAULT); <br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO) <br />return FALSE; <br /><br /><br />sword OCISessionEnd (  <br />OCISvcCtx       *svchp, <br />                       OCIError        *errhp, <br />                       OCISession      *usrhp, <br />                      ub4             mode ); <br />6．读取错误信息 <br />    sword OCIErrorGet ( <br />dvoid      *hndlp, //错误句柄 <br />                     ub4        recordno,//从那里读取错误记录，从1开始 <br />                     text       *sqlstate,//已取消，=NULL <br />                     sb4        *errcodep, //错误号 <br />                     text       *bufp,  //错误内容 <br />                     ub4        bufsiz,  //bufp长度 <br />                     ub4        type //传递的错误句柄类型 <br />=OCI_HTYPE_ERROR:错误句柄 <br />=OCI_HTYPE_ENV：环境句柄 <br />); <br />eg: <br /> ub4    ub4RecordNo = 1; <br />OCIError* hError <br />sb4    sb4ErrorCode; <br />char   sErrorMsg[1024]; <br /><br />if (OCIErrorGet(hError, ub4RecordNo++, NULL, &amp;sb4ErrorCode, (OraText*) sErrorMsg, sizeof(sErrorMsg), OCI_HTYPE_ERROR) == OCI_SUCCESS)
<br />       printf(“error msg:%s\n”, sErrorMsg); <br /><br /><br />7．准备SQL语句 <br />sword OCIStmtPrepare (  <br />OCIStmt       *stmtp,//语句句柄   <br />                   OCIError      *errhp, <br />                        CONST text    *stmt,  //SQL语句 <br />                        ub4           stmt_len,   //语句长度 <br />                        ub4           language,  //语句的语法格式=OCI_NTV_SYNTAX <br />ub4           mode //=OCI_DEFAULT <br />); <br /><br />eg: <br /> char sSQL[1024]; <br /><br />sprintf(sSQL, “select table_name from user_tables”); <br /><br />swResult = OCIStmtPrepare(stmtp errhp,  (CONST OraText*)sSQL, strlen(sSQL), OCI_NTV_SYNTAX, OCI_DEFAULT); <br />if(swResult != OCI_SUCCESS &amp;&amp; swResult != OCI_SUCCESS_WITH_INFO) <br />return FALSE; <br /><br /><br /><br /><br />8． 绑定输入参数 <br /><br />OCIBindArrayOfStruct()  Set skip parameters for static array bind ，数组绑定，一般用于批量操作  <br />OCIBindByName() Bind by name  按名绑定 <br />OCIBindByPos() Bind by position  按位置绑定,建议一般按此方式绑定 <br />OCIBindDynamic() Sets additional attributes after bind with OCI_DATA_AT_EXEC mode   <br />OCIBindObject() Set additional attributes for bind of named data type  <br /><br />注： <br />OCIBindArrayOfStruct必须先用OCIBindByPos初始化，然后在OCIBindArrayOfStruct中定义每个参数所跳过的字节数。 <br />如： <br /><br />存储方式： <br /><br /><br /><br />第一条记录第二条记录 N <br /><br /><br />  SkipPara(实际就是结构体长度，即本次所有列的长度和) <br /><br /><br /><br />sword OCIBindByName (  <br />OCIStmt       *stmtp, //语句句柄 <br />                 OCIBind       **bindpp,//结合句柄,=NULL <br />                 OCIError      *errhp, <br />                 CONST text    *placeholder,//占位符名称 <br />                 sb4           placeh_len, //占位符长度 <br />                 dvoid         *valuep, //绑定的变量名 <br />                 sb4           value_sz, //绑定的变量名长度 <br />                 ub2           dty,  //绑定的类型 <br />                 dvoid         *indp, //指示符变量指针(sb2类型),单条绑定时为NULL, <br />                 ub2           *alenp, //说明执行前后被结合的数组变量中各元素数据实际的长度，单条绑定时为NULL <br />                 ub2           *rcodep,//列级返回码数据指针，单条绑定时为NULL <br />                 ub4           maxarr_len, //最多的记录数,如果是单条绑定，则为0 <br />                 ub4           *curelep, //实际的记录数,单条绑定则为NULL <br />                 ub4           mode //=OCI_DEFAULT <br />);  <br /><br />sword OCIBindByPos ( OCIStmt      *stmtp,  <br />                     OCIBind      **bindpp, <br />                     OCIError     *errhp, <br />                     ub4          position,// 绑定的位置 <br />                     dvoid        *valuep, <br />                     sb4          value_sz, <br />                     ub2          dty, <br />                     dvoid        *indp, <br />                     ub2          *alenp, <br />                     ub2          *rcodep, <br />                     ub4          maxarr_len, <br />                     ub4          *curelep,  <br />                     ub4          mode ); <br /><br />sword OCIBindArrayOfStruct ( <br />OCIBind     *bindp,//绑定的结构句柄,由OCIBindByPos定义 <br />                 OCIError    *errhp, <br />                 ub4         pvskip, //下一列跳过的字节数** <br />                 ub4         indskip,//下一个指示器或数组跳过的字节数  <br />                 ub4         alskip, //下一个实际值跳过的字节数 <br />                 ub4         rcskip //下一个列级返回值跳过的字节数 <br />); <br /><br />例： <br />sword     swResult; <br />OCIBind*  hBind; <br />Ub4 rec_num; <br />Sql:  insert into student values (:p1,:p2) <br /><br />单条绑定： <br />hBind = NULL; <br />swResult = OCIBindByPos(stmtp &amp;hBind, errhp,1,ststd.tname,  <br />sizeof(ststd.tname), SQLT_CHR, NULL,  <br />NULL,NULL,0, NULL, OCI_DEFAULT); <br /><br /><br />批量取数据，一次取100条 <br />Sql:  select username,age from student where username=:p1 and age=:p2 <br /><br />hBind = NULL; <br />swResult = OCIBindByPos(stmtp &amp;hBind, errhp,1,tstd[0].tname,  <br />sizeof(tstd[0].tname), SQLT_CHR, &amp;tstdInd.sb2_usernmae[0],  <br />&amp;tstdLen.ub2_username[0],&amp;tstdRet.ub2_username[0],100, &amp;rec_num, OCI_DEFAULT); <br />swResult = OCIBindArrayOfStruct(hBind, errhp,sizeof(tstd [0]), sizeof(sb2), sizeof(ub2), sizeof(ub2)); <br /><br />9．执行SQL语句 <br />sword OCIStmtExecute (  <br />OCISvcCtx           *svchp,  //服务环境句柄 <br />                        OCIStmt             *stmtp,  //语句句柄 <br />                        OCIError            *errhp, <br />                        ub4                 iters, // ** <br />                        ub4                 rowoff, //** <br />                        CONST OCISnapshot   *snap_in, <br />                        OCISnapshot         *snap_out, <br />                        ub4                 mode //** <br />); <br /> **注： <br />1. iters:对于select语句，它说明一次执行读取到buffer中的记录行数，如果不能确定select语句所返回的行数，可将iters设置为0,而对于其他的语句，iters表示这些语句的执行次数，此时iters不能为0。 <br />2. rowoff:在多行执行时，该参数表示从所结合的数据变量中的第几条记录开始执行(即记录偏移量)。 <br />3. mode：=OCI_DEFAULT:default模式 <br />=OCI_DESCRIBE_ONLY：描述模式，只返回选择列表的描述信息，而不执行语句 <br />=OCI_COMMIT_ON_SUCCESS：自动提交模式，当执行成功后，自动提交。 <br />=OCI_EXACT_FETCH:精确提取模式。 <br />=OCI_BATCH_ERRORS：
批错误执行模式：用于执行数组方式的操作，在此模式下，批量insert ,update,delete时，执行过程中任何一条记录错误不会导致整个
insert ,update,delete失败，系统自动会收集错误信息，而在非批错误方式下，其中的任何一条记录错误，将会导致整个操作失败。 <br />Eg: <br />执行一次 <br />swResult = OCIStmtExecute(svchp, stmtp,  errhp；, <br />                      1, 0, NULL, NULL, OCI_DEFAULT); <br />批量执行100次： <br />swResult = OCIStmtExecute(svchp, stmtp,  errhp；, <br />                      100, 0, NULL, NULL, OCI_DEFAULT); <br /><br />10．定义输出变量 <br /><br />OCIDefineArrayOfStruct()   Set additional attributes for static array define   <br />OCIDefineByPos()   Define an output variable association   <br />OCIDefineDynamic()   Sets additional attributes for define in OCI_DYNAMIC_FETCH mode   <br />OCIDefineObject()   Set additional attributes for define of named data type   <br /><br />sword OCIDefineByPos (  <br />OCIStmt     *stmtp, //语句句柄  <br />                       OCIDefine   **defnpp,//定义句柄—用于数组变量 <br />                       OCIError    *errhp, <br />                       ub4         position,//位置序号(从1 开始) <br />                       dvoid       *valuep, //输出的变量名 <br />                       sb4         value_sz, //变量长度 <br />                       ub2         dty,  //数据类型 <br />                       dvoid       *indp, //指示器变量/指示器变量数组，如果此字段可能存在空值，则要指示器变量，否则单条处理时为NULL <br />                       ub2         *rlenp, //提取的数据长度 <br />                       ub2         *rcodep, //列级返回码数组指针 <br />ub4         mode //OCI_DEFAULT <br />); <br /><br /><br /><br /><br />sword OCIDefineArrayOfStruct (  <br />OCIDefine   *defnp,//由OCIDefineByPos定义的句柄 <br />                 OCIError    *errhp, <br />ub4         pvskip, //下一列跳过的字节数,一般就是结构的大小 <br />                 ub4         indskip,//下一个指示器或结构跳过的字节数,=0  <br />                 ub4         rlskip, //下一个实际值跳过的字节数,=0 <br />                 ub4         rcskip //下一个列列级返回值跳过的字节数,=0 <br />); <br /><br />sword OCIDefineDynamic (  <br />OCIDefine   *defnp, <br />                         OCIError    *errhp, <br />                         dvoid       *octxp,  <br />                         OCICallbackDefine       (ocbfp)(/*_ <br />                                  dvoid          *octxp, <br />                                  OCIDefine      *defnp, <br />                                  ub4            iter,  <br />                                  dvoid          **bufpp, <br />                                  ub4            **alenpp, <br />                                  ub1            *piecep, <br />                                  dvoid          **indpp, <br />                                  ub2            **rcodep _*/)  ); <br /><br />sword OCIDefineObject ( OCIDefine       *defnp, <br />                        OCIError        *errhp, <br />                        CONST OCIType   *type, <br />                        dvoid           **pgvpp,  <br />                        ub4             *pvszsp,  <br />                        dvoid           **indpp,  <br />                        ub4             *indszp ); <br /><br />eg: <br />单条查询 <br />sql: select username,age from student  where username=:p1; <br /> 如果此字段有可能有空值，则 <br />hDefine = NULL; <br />swResult = OCIDefineByPos(stmtp &amp;hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, &amp; sb2aInd[0], NULL, NULL, OCI_DEFAULT);
<br />如果此字段没有空值，则 <br />hDefine = NULL; <br />swResult = OCIDefineByPos(stmtp &amp;hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT);
<br /><br />  批量查询 <br />select username,age from student  where age&gt;30; <br />hDefine = NULL; <br />swResult = OCIDefineByPos(stmtp, &amp;hDefine, errhp, 1, &amp;tstd[0].username,  <br />sizeof(tstd[0].usenmae), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT); <br /><br />swResult = OCIDefineArrayOfStruct(hDefine, errhp, sizeof(tstd[0]), 0, 0, 0); <br />11．提取结果 <br />sword OCIStmtFetch ( <br />OCIStmt     *stmtp,//语句句柄 <br />                     OCIError    *errhp,  <br />                     ub4         nrows, //从当前位置处开始一次提取的记录数，对于数据变量，可以&gt;1,否则不能&gt;1 <br />                     ub2         orientation,//提取的方向：OCI_FETCH_NEXT <br />ub4         mode //OCI_DEFAULT <br />   ) <br /><br />eg <br />   while ((swResult=OCIStmtFetch stmtp errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT)) != OCI_NO_DATA) <br />{ <br />…… <br />} <br /><br />12．事务操作 <br />开始一个事务 <br />sword OCITransStart (  <br />OCISvcCtx    *svchp,  <br />                      OCIError     *errhp,  <br />                      uword        timeout, //**  <br />                      ub4          flags ); <br />**注： <br />1． Timeout: <br />当flag=OCI_TRANS_RESUME:它表示还有多少秒事务将被激活 <br />=OCI_TRANS_NEW: 事务响应的超时时间(秒) <br />2． Flags:指定一个新的事务还是已有事务 <br />=OCI_TRANS_NEW：定义一个新的事务 <br />=OCI_TRANS_RESUME <br /><br />准备一个事务： <br />sword OCITransPrepare ( <br /> OCISvcCtx    *svchp,  <br />                        OCIError     *errhp, <br />                        ub4          flags );//OCI_DEFAULT <br /><br />sword OCITransForget (  <br />OCISvcCtx     *svchp,  <br />                       OCIError      *errhp, <br />                       ub4           flags );//OCI_DEFAULT <br /><br />断开一个事务： <br />sword OCITransDetach (  <br />OCISvcCtx    *svchp, <br />                       OCIError     *errhp, <br />ub4          flags );//OCI_DEFAULT <br /><br />  提交一个事务： <br /> sword OCITransCommit ( <br />OCISvcCtx    *svchp,  //服务环境句柄 <br />                              OCIError     *errhp, <br />                              ub4          flags ); //OCI_DEFAULT <br />回滚一个事务 <br />sword OCITransRollback ( <br />dvoid        *svchp,  <br />                              OCIError     *errhp, <br />                              ub4          flags ); //OCI_DEFAULT <br /><br /><br />四． OCI数据类型与C语言数据类型对照表 <br />表字段类型 　　　　　OCI类型 C类型 备注 <br />Number(N) SQLT_UIN 　int 无符号整型 <br />Number(N) SQLT_INT 　int 有符号整型 <br />Number(n,m) SQLT_FLT 　float 符点数 <br />Varchar2(N) Sqlt_chr　　Char 字符串 <br />Raw(N) 　　Sqlt_BIN 具体看不同的定义 二进制类型，多用于一个结构字段 <br />DATE SQLT_DAT 无 最好转换成字符串或数字<br /><br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=582980</p><img src ="http://www.cppblog.com/guangping/aggbug/27605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-07-06 15:44 <a href="http://www.cppblog.com/guangping/archive/2007/07/06/27605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于VC++ 2005下开发ActiveX控件时,属性和属性页控件值关联的困惑</title><link>http://www.cppblog.com/guangping/archive/2007/07/05/27513.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Thu, 05 Jul 2007 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/07/05/27513.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/27513.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/07/05/27513.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/27513.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/27513.html</trackback:ping><description><![CDATA[以下内容如果不明白，可以看一下孙鑫&lt;&lt;VC深入详解&gt;&gt;教程第18课的"clock"控件实例，内容摘自网友帖，因本人亦有此困惑，故记之。<br /><br /><br />我刚开始学习ActiveX开发,使用MFC。我对ActiveX控件新增一个名为"Caption",类型为int的属性.我在ActiveX的属性页上新增一个Edit control,想通过该Edit control来直接设置"Caption"属性的值.<br />现在问题来了:<br />在VC6.0中开发时可以通过class wizard的"增加成员变量"来直接将该Edit control与"Caption"属性关联.生成的代码在DoDataExchange方法中如下:<br /><br />void CCircPropPage::DoDataExchange(CDataExchange* pDX)<br />{<br />//{{AFX_DATA_MAP(CCircPropPage)<br />DDP_Text(pDX, IDC_CAPTION, m_caption, _T("Caption") );//(1)<br />DDX_Text(pDX, IDC_CAPTION, m_caption);<br />//}}AFX_DATA_MAP<br />DDP_PostProcessing(pDX);<br />}<br /><br />其中(1)行的最一个参数:_T("Caption") ,就是该Edit control所关联的属性名.<br /><br />但
在VC++ 2005中,却没有直接将Edit control与属性相关联的功能.在VC++ 2005中在Edit
control上右击,选择"添加变量",打开"添加成员变量向导",但该向导只能添加与Edit
control关联的"成员变量",无法将该Edit control 与"Caption"属性关联.VC++ 2005生成的代码如下:<br /><br />void CCircPropPage::DoDataExchange(CDataExchange* pDX)<br />{<br />//{{AFX_DATA_MAP(CCircPropPage)<br />//DDP_Text(pDX, IDC_CAPTION, m_caption, _T("Caption") );//(1)//这是VC6生成的代码，这里留作参照<br />//DDX_Text(pDX, IDC_CAPTION, m_caption);//这也是VC6生成的<br />//}}AFX_DATA_MAP<br />DDP_PostProcessing(pDX);   //(2)<br />DDX_Text(pDX, IDC_CAPTION1, m_caption1);//&lt;--(3) VC++产生的代码.<br />}<br /><br />其
中第(3)行为VC++
2005产生的代码.它并没有调用DDP_系列的函数,也将代码放在了AFX_DATA_MAP宏的外面、第(2)行的下面(第2行函数的功能为:结束属
性值与Control的转换),也就是说VC++ 2005并没有将Edit control与属性关联的功能!??<br />虽然可以通过手动添加方式解决,但我总觉得VC++ 2005应该提供如此功能,不知道有没有朋友遇到过与我相同的问题,如何解决之?<br /><br />难道，正如别人所说，VC2005比VC6是一个退步。<br /><img src ="http://www.cppblog.com/guangping/aggbug/27513.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-07-05 10:03 <a href="http://www.cppblog.com/guangping/archive/2007/07/05/27513.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC消息映射机制的剖析(孙鑫VC++讲座笔记-(4)转载并修改)</title><link>http://www.cppblog.com/guangping/archive/2007/03/02/19106.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Fri, 02 Mar 2007 01:58:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/03/02/19106.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/19106.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/03/02/19106.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/19106.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/19106.html</trackback:ping><description><![CDATA[
		<p>一，消息映射机制</p>
		<p>1，消息响应函数：（例：在CDrawView类响应鼠标左键按下消息）<br /> 1）在头文件(DrawView.h)中声明消息响应函数原型。<br />//{{AFX_MSG(CDrawView)   //注释宏<br />afx_msg void OnLButtonDown(UINT nFlags, CPoint point);<br />//}}AFX_MSG   //注释宏<br />说明：<br />在注释宏之间的声明在VC中灰色显示。afx_msg宏表示声明的是一个消息响应函数。 <br /></p>
		<p>这个注释宏为的是让ClassWizard能够分辨出哪些代码是它生成的，哪些是你自己写的。<br />你自己写的代码要在这个注释之外，这样ClassWizard再修改消息映射的时候就不会管你的代码了。<br />限于以前的硬件速度，ClassWizard比较傻冒，所以需要这些注释宏来定位。从7.0开始，就不再需<br />要了。新的属性页能够自动分析你的代码，为你添加或者删除代码，而无需什么特殊标记的帮忙。<br />因此注释宏已经是历史产物了。</p>
		<div align="left">
		</div>
		<p> 2）在源文件（DrawView.cpp)中进行消息映射。<br />BEGIN_MESSAGE_MAP(CDrawView, CView)<br /> //<!-- NAPS variable {AFX_MSG_MAP(CDrawView)<br/> ON_WM_LBUTTONDOWN()<br/> // undefined -->}AFX_MSG_MAP<br /> // Standard printing commands<br /> ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)<br /> ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)<br /> ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)<br />END_MESSAGE_MAP()<br />说明：<br />在宏BEGIN_MESSAGE_MAP()与END_MESSAGE_MAP()之间进行消息映射。<br />宏ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN与它的响应函数OnLButtonDown（）相关联。这样一旦有消息的产生，就会自动调用相关联的消息响应函数去处理。<br />宏ON_WM_LBUTTONDOWN()定义如下：<br />#define ON_WM_LBUTTONDOWN() <br /> { WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, <br />  (AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, CPoint))&amp;OnLButtonDown },<br /> 3）源文件中进行消息响应函数处理。（DrawView.cpp中自动生成OnLButtonDown函数轮廓，如下）<br />void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) <br />{<br /> // TODO: Add your message handler code here and/or call default<br /> CView::OnLButtonDown(nFlags, point);<br />}<br />说明：<br />可见当增加一个消息响应处理，在以上三处进行了修改。可在消息响应函数里添加消息处理代码完成对消息的响应、处理。</p>
		<p>2，消息响应的方式：<br />1）
在基类中针对每种消息做一个虚函数，当子类对消息响应时候，只要在子类中重写这个虚函数即可。缺点：MFC类派生层次很多，如果在基类对每个消息进行虚函
数处理，那么从基类派生的每个子类都将背负一个庞大的虚表，这样浪费内存，故MFC没有采取这中方式而采取消息映射方式。<br />2）消息映射方式：
MFC在后台维护了一个句柄和C++对象指针对照表，当收到一个消息后，通过消息结构里资源句柄（查对照表）就可找到与它对应的一个C++对象指针，然后
把这个指针传给基类，基类利用这个指针调用WindowProc()函数对消息进行处理，WindowProc()函数中调用OnWndMsg()函数，
真正的消息路由及处理是由OnWndMsg()函数完成的。由于WindowProc()和OnWndMsg()都是虚函数，而且是用派生类对象指针调用
的，由多态性知最总终调用子类的。在OnWndMsg()函数处理的时候，根据消息种类去查找消息映射，判断所发的消息有没有响应函数，具体方式是到相关
的头文件和源文件中寻找消息响应函数声明（从注释宏//<!-- NAPS variable {AFX_MSG(CDrawView)...// undefined -->}AFX_MSG之间寻找），消息映射（从宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之间寻找），最终找到对应的消息处理函数。当然，如果子类中没有对消息进行处理，则消息交由基类处理。<br />说明：<br />virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);<br />virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);</p>
<img src ="http://www.cppblog.com/guangping/aggbug/19106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-03-02 09:58 <a href="http://www.cppblog.com/guangping/archive/2007/03/02/19106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用wxDb（ODBC）连接Excel sheet</title><link>http://www.cppblog.com/guangping/archive/2007/01/30/18180.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Tue, 30 Jan 2007 06:13:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/01/30/18180.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/18180.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/01/30/18180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/18180.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/18180.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td width="100%">
										<span class="postdetails">
												<b>发表主题: 用wxDb（ODBC）连接Excel sheet</b>
										</span>
								</td>
								<td valign="top" nowrap="">
										<a href="http://www.zhidun.com/phpbb/posting.php?mode=quote&amp;p=2597&amp;sid=ab967338a00fe70b4d89a33579258a27">
										</a>
								</td>
						</tr>
						<tr>
								<td colspan="2">
										<hr />
								</td>
						</tr>
						<tr>
								<td colspan="2">
										<span class="postbody">碰到个活要读取Excel文件中的数据，搜了一下Excel有ODBC驱动可以使用，碰巧wxWidgets又有ODBC模块，真是可以省掉不少事情。本以为可以轻松搞定，不料一直没有能连接上，郁闷了一阵子，后来在RTFS的原则下终于调试出，原来是wxDb的一个bug,修复和提交patch后，问题解决。 <br /><br />bug submission: <br /><a href="https://sourceforge.net/tracker/?func=detail&amp;atid=309863&amp;aid=1494705&amp;group_id=9863" target="_blank">https://sourceforge.net/tracker/?func=detail&amp;atid=309863&amp;aid=1494705&amp;group_id=9863</a><br /><br />使用范例： <br />wxString s = wxT("DRIVER={Microsoft Excel Driver (*.xls)};DSN='''';DBQ=")+filename; <br />wxDbConnectInf dbi; <br />dbi.SetConnectionStr(s); <br />dbi.AllocHenv(); <br />db = new wxDb(dbi.GetHenv()); <br />db-&gt;Open(&amp;dbi);//this line failed if not patched <br /><br /><br />在后面提取数据的时候，需要提供table名字，Excel比较特殊，不是直观的关系型数据库那样可以看到table的存在。方法是： <br />选定数据区域,菜单-&gt;插入-&gt;名称-&gt;定义,里面输入的名字就是table名称。 <br /><br />提取table的例子： <br />if(db-&gt;TableExists(wxT("ryzl"))){ <br />UWORD n; <br />wxDbColInf *cols = db-&gt;GetColumns(wxT("ryzl"),&amp;n); <br />if(cols == NULL){ <br />wxMessageBox(wxT("no no get")); <br />}else{ <br />wxMessageBox(wxString::Format(wxT("we got %d"),(int)n)); <br />} <br />}else{ <br />wxMessageBox(wxT("table ryzl not exists")); <br />}</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/guangping/aggbug/18180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-01-30 14:13 <a href="http://www.cppblog.com/guangping/archive/2007/01/30/18180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wxODBC(wxWidgets)中使用驱动程序方式打开数据库</title><link>http://www.cppblog.com/guangping/archive/2007/01/29/18150.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Mon, 29 Jan 2007 09:34:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2007/01/29/18150.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/18150.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2007/01/29/18150.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/18150.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/18150.html</trackback:ping><description><![CDATA[
		<p>wxODBC(wxWidgets)中使用驱动程序方式打开数据库</p>
		<p>wxWidgets的文档中都是使用在控制面板/数据源中设定DSN来创建ODBC连接。但是实际上很多小型的应用，只是使用本机的一个Access数据库。而要求使用者学习ODBC的DSN配置明显的增加了软件的使用难度。因此，研究了一下wxforum.org中的帖子，试验成功！范例如下：</p>
		<p>wxDbConnectInf *DbConnectInf = NULL; // 定义数据库连接信息指针DB connection information<br />wxDb *PodDB = NULL; // 定义数据库连接指针Database connection<br />wxDbTable *table = NULL; // 定义数据表指针Data table to access </p>
		<p>DbConnectInf = new wxDbConnectInf(0, wxT(""), wxT(""), wxT(""));//这里定义的内容基本没用，但不定义会报错</p>
		<p>PodDB = new wxDb(DbConnectInf-&gt;GetHenv());</p>
		<p>bool DBfailOnDataTypeUnsupported=!true;//<br />if(!DB-&gt;Open(wxT("DRIVER=Microsoft Access Driver (*.mdb);DBQ=D:\\pod.mdb;UID=admin;"),DBfailOnDataTypeUnsupported))//使用驱动程序的方式打开数据库<br />{<br />if (PodDB-&gt;IsOpen())<br />{<br />// Connection is open, but the initialization of<br />// datatypes and parameter settings failed<br />return 0;<br />}<br />else<br />{<br />// Error opening datasource<br />//return HandleError(wxT("DB ENV ERROR: Cannot allocate ODBC env handle"));<br />return 0;<br />}<br />}<br />const wxString tableName = wxT("POD"); //定义要操作的表的名称<br />const UWORD numTableColumns = 8; //指出POD表中的列数（columns）<br />//建立到表的连接<br />table = new wxDbTable(PodDB, tableName, numTableColumns, wxT(""), wxDB_QUERY_ONLY, wxT(""));</p>
		<p>//将存放提取数据的变量清空<br />wxStrcpy(pPodPictureInfo-&gt;Title, wxT(""));<br />......</p>
		<p>//定义列的数据格式，和取出的格式。<br />//此处需要注意的是如果前面指明了numTableColumns为n的话，就一定要定义n条<br />table-&gt;SetColDefs(0, wxT("Pod_Title"), DB_DATA_TYPE_VARCHAR, pPodPictureInfo-&gt;Title, SQL_C_WXCHAR, sizeof(pPodPictureInfo-&gt;Title), true, true);<br />......</p>
		<p>//打开表<br />if (!table-&gt;Open())<br />{<br />//An error occurred opening (setting up) the table"));<br />}</p>
		<p>//限定取出Pod_When列值为1982的行(row)<br />table-&gt;SetWhereClause(wxT("Pod_When = '1982'"));</p>
		<p>//按照PodDate字段排序<br />table-&gt;SetOrderByClause(wxT("Pod_Date"));</p>
		<p>//根据上面的限定信息执行查询操作<br />if (!table-&gt;Query())<br />{<br />return HandleError(wxT("QUERY ERROR: "), table-&gt;GetDb());<br />//return 0;<br />}</p>
		<p>while (table-&gt;GetNext())//提取查询到的行<br />{<br />wxString msg; // Used for display messages<br />msg.Printf(wxT("Row #% lu --\nTitle : %s\nPodDate : %s\nWhere : %s\nWhen : %s\nWho : %s\nDisc : %s\nRelated : %s\nPhotoName :%s"),<br />table-&gt;GetRowNum(),<br />pPodPictureInfo-&gt;Title,<br />pPodPictureInfo-&gt;PodDate,<br />pPodPictureInfo-&gt;Where,<br />pPodPictureInfo-&gt;When,<br />pPodPictureInfo-&gt;Who,<br />pPodPictureInfo-&gt;Disc,<br />pPodPictureInfo-&gt;Related,<br />pPodPictureInfo-&gt;PhotoName<br />);<br />//检查表操作/现实获取的POD信息<br />//wxSafeShowMessage(wxT("Pod_wxDbTable Test"),msg);<br />}</p>
		<p>
				<br />------补充一点------</p>
		<p>在SetColDefs中关联的变量不能使用wxString，只能使用wxChar[n]等格式。</p>
		<p>
		</p>
		<p>
				<br />struct PodPictrueInfo<br />{<br />wxChar Title[100];<br />......</p>
		<p>}</p>
		<p>
		</p>
<img src ="http://www.cppblog.com/guangping/aggbug/18150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2007-01-29 17:34 <a href="http://www.cppblog.com/guangping/archive/2007/01/29/18150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于完美的C++开发环境的思考</title><link>http://www.cppblog.com/guangping/archive/2006/05/08/6745.html</link><dc:creator>阿光</dc:creator><author>阿光</author><pubDate>Mon, 08 May 2006 06:55:00 GMT</pubDate><guid>http://www.cppblog.com/guangping/archive/2006/05/08/6745.html</guid><wfw:comment>http://www.cppblog.com/guangping/comments/6745.html</wfw:comment><comments>http://www.cppblog.com/guangping/archive/2006/05/08/6745.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/guangping/comments/commentRss/6745.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guangping/services/trackbacks/6745.html</trackback:ping><description><![CDATA[我一直在寻求着一个完美的C++开发环境组合，我期望的完美是这样的：
1、跨平台的，这可以保证我的一次智力学习投资，获得多方面的收宜。
2、开放的，至少不会因为某一个商业行为而消亡，像dephi就有点前景不妙。
3、可自由配置的，我可以任意选择自已喜欢的编译器，而不是由它来指定；我可以选择自已喜欢的类库，而不是非它自已的库不可。
4、有着清爽不繁杂，友好又不霸道，灵活又不失习惯标准的可视化操作环境。
5、是基于代码效率最高化为目标，兼容性占第一位的。不要像那些非要装个 .net或jre这类的，讨人烦。
6、必须要100%支持C++最新标准的。
7、当然，软件的体积不能太大，太消耗资源的软件，也是很难让人接受的。

根据以上的想法：
   我目前的C++环境是这样组合的：
    Code::blocks + mingw + wxWidget＋DialogBlocks 
   前三样都是开源的，跨平台的，可自由配置的。最后一样是为了配合wxWidget而选择的，是商业软件，这不能不说是个遗憾，但目前还没找到一个功能上能比的上它，又开源免费的工具。只能期望有更多的志愿者作奉献了。但是Code::blocks本身没有一个理想的GUI设计器确实太缺憾了，它自身的smith虽然是GUI设计器，但远还不成熟，所以只好配合DialogBlocks。

不能不说，为什么这么多年来，就没有一个称心的开发工具呢？这样的日子真的永远不会到来吗？
<img src ="http://www.cppblog.com/guangping/aggbug/6745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guangping/" target="_blank">阿光</a> 2006-05-08 14:55 <a href="http://www.cppblog.com/guangping/archive/2006/05/08/6745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>