﻿<?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++博客-吃桃子还是苹果</title><link>http://www.cppblog.com/pwqonline/</link><description>我吃桃子</description><language>zh-cn</language><lastBuildDate>Fri, 03 Apr 2026 18:50:15 GMT</lastBuildDate><pubDate>Fri, 03 Apr 2026 18:50:15 GMT</pubDate><ttl>60</ttl><item><title>char型数字转换成int型</title><link>http://www.cppblog.com/pwqonline/archive/2009/03/02/75272.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Sun, 01 Mar 2009 16:04:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2009/03/02/75272.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/75272.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2009/03/02/75272.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/75272.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/75272.html</trackback:ping><description><![CDATA[假设定义了<br>&nbsp;&nbsp;&nbsp;char a = '2';<br>&nbsp;&nbsp;&nbsp;int b;<br>怎么将a的2赋值到b中呢？<br>想像一下ASCII中'0'的值是48，所以可以有以下两种方法<br>1、<br>&nbsp;&nbsp;&nbsp;b = a -48;<br>2、<br>&nbsp;&nbsp;&nbsp;b = a - '0';<br>如果是字符串则加头文件<br>&nbsp;&nbsp;&nbsp;#include&lt;stdlib.h&gt;<br>然后使用atoi即可。
<img src ="http://www.cppblog.com/pwqonline/aggbug/75272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2009-03-02 00:04 <a href="http://www.cppblog.com/pwqonline/archive/2009/03/02/75272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符数组，字符指针，字符串常量以及其sizeof的一些总结</title><link>http://www.cppblog.com/pwqonline/archive/2009/03/01/75269.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Sun, 01 Mar 2009 15:55:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2009/03/01/75269.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/75269.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2009/03/01/75269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/75269.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/75269.html</trackback:ping><description><![CDATA[<p><strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong>以字符串形式出现的，编译器都会为该字符串自动添加一个<span>0</span>作为结束符。</strong></p>
<p>如在代码中写<span>"abc",</span>那么编译器帮你存储的是<span>"abc\0"</span>。</p>
<p><strong><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>"abc"</span>是常量吗？</strong></p>
<p>答案是有时是、有时不是。</p>
<p>不是常量的情况：<span>"abc"</span>作为字符数组初始值的时候就不是，如<span>:</span></p>
<p><span>char str[] = "abc";</span></p>
<p>因为定义的是一个字符数组，所以就相当于定义了一些空间来存放<span>"abc",</span>又因为字符数组就是把字符一个一个地存放的，所以编译器把这个语句解析为</p>
<p><span>char str[3] = {'a','b','c'};</span></p>
<p>又根据上面的总结<span>1</span>，所以<span>char str[] = "abc";</span>的最终结果是<span>:</span></p>
<p><span>char str[4] = {'a','b','c','\0'};</span></p>
<p>做一下扩展，如果<span>char str[] = "abc";</span>是在函数内部写的话，那么这里的<span>"abc\0"</span>因为不是常量，所以应该被放在栈上。<span><br><br></span>是常量的情况： 把<span>"abc"</span>赋给一个字符指针变量时，如：</p>
<p><span>char* ptr = "abc";</span></p>
<p>因为定义的是一个普通指针，并没有定义空间来存放<span>"abc"</span>，所以编译器得帮我们找地方来放<span>"abc"</span>，显然，把这里的<span>"abc"</span>当成常量并把它放到程序的常量区是编译器最合适的选择。所以尽管<span>ptr</span>的类型不是<span>const char*</span>，并且<span>ptr[0] = 'x';</span>也能编译通过，但是执行<span>ptr[0] = 'x';</span>就会发生运行时异常，因为这个语句试图去修改程序常量区中的东西。</p>
<p>记得哪本书中曾经说过<span>char* ptr = "abc";</span>这种写法原来在<span>c++</span>标准中是不允许的，但是因为这种写法在<span>c</span>中实在是太多了，为了兼容<span>c</span>，不允许也得允许。虽然允许，但是建议的写法应该是<span>const char* ptr = "abc";</span>这样如果后面写<span>ptr[0] = 'x'</span>的话编译器就不会让它编译通过，也就避免了上面说的运行时异常。又扩展一下，如果<span>char* ptr = "abc";</span>写在函数体内，那么虽然这里的<span>"abc\0"</span>被放在常量区中，但是<span>ptr</span>本身只是一个普通的指针变量，所以<span>ptr</span>是被放在栈上的，只不过是它所指向的东西被放在常量区罢了。</p>
<p><strong><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong>数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。</strong></p>
<p>如<span>char s1[3]</span>和<span>char s2[4]</span>，<span>s1</span>的类型就是<span>char[3]</span>，<span>s2</span>的类型就是<span>char[4]</span>，<span><br></span>也就是说尽管<span>s1</span>和<span>s2</span>都是字符数组，但两者的类型却是不同的。</p>
<p><strong><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong>字符串常量的类型可以理解为相应字符常量数组的类型。</strong></p>
<p>如<span>"abcdef"</span>的类型就可以看成是<span>const char[7]</span>。</p>
<p><strong><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>sizeof</span>是用来求类型的字节数的。</strong></p>
<p>如<span>int a;</span>那么无论<span>sizeof(int)</span>或者是<span>sizeof(a)</span>都是等于<span>4</span>，因为<span>sizeof(a)</span>其实就是<span>sizeof(type of a)</span>。</p>
<p><strong><span><span>6.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong>对于函数参数列表中的以数组类型书写的形式参数，编译器把其解释为普通的指针类型。</strong></p>
<p>如对于<span>void func(char sa[100],int ia[20],char *p)</span><span><br></span>则<span>sa</span>的类型为<span>char*</span>，<span>ia</span>的类型为<span>int*</span>，<span>p</span>的类型为<span>char*</span></p>
<p><strong><span><span>7.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong>根据上面的总结，来实战一下。</strong></p>
<p>对于<span>char str[] = "abcdef";</span></p>
<p>就有<span>sizeof(str) == 7,</span>因为<span>str</span>的类型是<span>char[7]</span>，也有<span>sizeof("abcdef") == 7</span>，因为<span>"abcdef"</span>的类型是<span>const char[7]</span>。</p>
<p>对于<span>char *ptr = "abcdef";</span></p>
<p><span>就有<span>sizeof(ptr) == 4</span>，因为<span>ptr</span>的类型</span>是<span>char*</span>。</p>
<p>对于<span>char str2[10] = "abcdef";</span></p>
<p><span>就有<span>sizeof(str2) == 10</span>，因为<span>st</span></span><span>r2</span>的类型是<span>char[10]</span>。</p>
<p>对于<span>void func(char sa[100],int ia[20],char *p);</span></p>
<p><span>就有<span>sizeof(sa) == sizeof(ia) == sizeof(p) == 4</span>，因为</span><span>sa</span>的类型是<span>char*</span>，<span>ia</span>的类型是<span>int*</span>，<span>p</span>的类型是<span>char*</span>。</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/pwqonline/aggbug/75269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2009-03-01 23:55 <a href="http://www.cppblog.com/pwqonline/archive/2009/03/01/75269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>printf输出与cout输出。</title><link>http://www.cppblog.com/pwqonline/archive/2009/02/20/74464.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Fri, 20 Feb 2009 14:53:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2009/02/20/74464.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/74464.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2009/02/20/74464.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/74464.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/74464.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 微软雅黑">首先说说printf与cout的区别</span><br style="FONT-FAMILY: 微软雅黑"><span style="FONT-FAMILY: 微软雅黑">printf是C语言中的输出方式</span><br style="FONT-FAMILY: 微软雅黑"><span style="FONT-FAMILY: 微软雅黑">此函数原型是：</span><br><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">int printf(const char *format, ...);</span><br><span style="FONT-FAMILY: 微软雅黑">可以看出来前面的const char *format是</span><span style="COLOR: #ff0000; FONT-FAMILY: 微软雅黑"><span style="COLOR: #140000">和</span>格式化有关</span><span style="FONT-FAMILY: 微软雅黑">；</span><br style="FONT-FAMILY: 微软雅黑"><span style="FONT-FAMILY: 微软雅黑">printf的调用方式为：</span><br><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">printf("&lt;格式化字符串&gt;", &lt;参量表&gt;);</span><br><span style="FONT-FAMILY: 微软雅黑">其中""中间的内容就是格式化字符串语句，他的作用是给出后出参量表中参量的输出形式，</span><br style="FONT-FAMILY: 微软雅黑"><span style="FONT-FAMILY: 微软雅黑">他的具体表现形式如下</span><br><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">int a = 10;</span><br style="FONT-FAMILY: courier new"><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">char b = 'a';</span><br style="FONT-FAMILY: courier new"><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">printf("%d%c",a,b);</span><br><span style="FONT-FAMILY: 微软雅黑">可以看出来"%d%c"和a、b的类型是有对应关系的，具体如下：</span><br><span style="FONT-FAMILY: Times New Roman">　　<span style="COLOR: #ff0000">%d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 十进制有符号整数 </span></span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 十进制无符号整数 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%f &nbsp; &nbsp; &nbsp; 浮点数 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 字符串 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 单个字符 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指针的值 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指数形式的浮点数 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %X 无符号以十六进制表示的整数 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无符号以八进制表示的整数 </span><br style="COLOR: #ff0000; FONT-FAMILY: Times New Roman"><span style="COLOR: #ff0000; FONT-FAMILY: Times New Roman">　　%g &nbsp; &nbsp;&nbsp; 自动选择合适的表示法</span><br><span style="FONT-FAMILY: 微软雅黑">而在</span><span style="FONT-FAMILY: 微软雅黑">"%d%c"中还可以插入一些其他值，比如<br></span><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">printf("%5d",a);</span><br><span style="FONT-FAMILY: 微软雅黑">表示输出5位整形数，不够5位右对齐。</span><br><span style="FONT-FAMILY: courier new; BACKGROUND-COLOR: yellow">printf("%-5d",a);<br></span><span style="FONT-FAMILY: 微软雅黑">就表示输出5位整形数，不够5位左对齐。</span><br><br><br><br>
<img src ="http://www.cppblog.com/pwqonline/aggbug/74464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2009-02-20 22:53 <a href="http://www.cppblog.com/pwqonline/archive/2009/02/20/74464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WM_CREATE消息响应函数和WM_INITDIALOG消息响应函数之区别</title><link>http://www.cppblog.com/pwqonline/archive/2008/11/25/67806.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Tue, 25 Nov 2008 06:03:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/11/25/67806.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/67806.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/11/25/67806.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/67806.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/67806.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在响应WM_CREATE消息响应函数的时候，对话框及子控件还未创建完成，亦是说只是通知系统说要开始创建窗口啦，这个消息响应完之后，对话框和子控件才开始创建。因此在此消息响应函数中无法对控件进行修改和初始化。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;而WM_INITDIALOG消息响应函数是在程序运行时，当其对话框和子控件全部创建完毕，将要显示内容的时候发送的消息。因此可以在WM_INITDIALOG消息响应函数中添加对编辑框控件的初始化和修改。 
<img src ="http://www.cppblog.com/pwqonline/aggbug/67806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-11-25 14:03 <a href="http://www.cppblog.com/pwqonline/archive/2008/11/25/67806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual   C++中函数调用方式</title><link>http://www.cppblog.com/pwqonline/archive/2008/11/20/67380.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Thu, 20 Nov 2008 06:42:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/11/20/67380.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/67380.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/11/20/67380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/67380.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/67380.html</trackback:ping><description><![CDATA[<div>我们知道在进行函数调用时，有几种调用方法，分为C式，Pascal式。在C和C++中C式调用是缺省的，除非特殊声明。二者是有区别的，下面我们用实例说明一下：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.&nbsp;&nbsp;&nbsp;__cdecl&nbsp;&nbsp;&nbsp;:C和C++缺省调用方式&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;例子：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;Input(&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&amp;m,int&nbsp;&nbsp;&nbsp;&amp;n);/*相当于void&nbsp;&nbsp;&nbsp;__cdecl&nbsp;&nbsp;&nbsp;Input(int&nbsp;&nbsp;&nbsp;&amp;m,int&nbsp;&nbsp;&nbsp;&amp;n);*/&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以下是相应的汇编代码：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00401068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lea&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,[ebp-8]&nbsp;&nbsp;&nbsp;;取[ebp-8]地址(ebp-8),存到eax&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0040106B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;然后压栈&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0040106C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lea&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,[ebp-4]&nbsp;&nbsp;&nbsp;;取[ebp-4]地址(ebp-4),存到ecx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0040106F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;然后压栈&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00401070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@ILT+5(Input)&nbsp;&nbsp;&nbsp;(0040100a);然后调用Input函数&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00401075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;恢复栈&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;从以上调用Input函数的过程可以看出：在调用此函数之前，首先压栈ebp-8,然后压栈ebp-4,然后调用函数Input,最后Input函数调用结束后，利用esp+8恢复栈。由此可见，在C语言调用中默认的函数修饰_cdecl，由主调用函数进行参数压栈并且恢复堆栈。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;下面看一下：地址ebp-8和ebp-4是什么？&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;在VC的VIEW下选debug&nbsp;&nbsp;&nbsp;windows,然后选Registers,显示寄存器变量值，然后在选debug&nbsp;&nbsp;&nbsp;windows下面的Memory,输入ebp-8的值和ebp-4的值(或直接输入ebp-8和-4)，看一下这两个地址实际存储的是什么值，实际上是变量&nbsp;&nbsp;&nbsp;n&nbsp;&nbsp;&nbsp;的地址(ebp-8),m的地址(ebp-4),由此可以看出：在主调用函数中进行实参的压栈并且顺序是从右到左。另外，由于实参是相应的变量的引用，也证明实际上引用传递的是变量的地址(类似指针)。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;总结：在C或C++语言调用中默认的函数修饰_cdecl，由主调用函数进行参数压栈并且恢复堆栈，实参的压栈顺序是从右到左，最后由主调函数进行堆栈恢复。由于主调用函数管理堆栈，所以可以实现变参函数。另外，命名修饰方法是在函数前加一个下划线(_).&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;&nbsp;&nbsp;WINAPI&nbsp;&nbsp;&nbsp;(实际上就是PASCAL，CALLBACK,_stdcall)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;例子：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;WINAPI&nbsp;&nbsp;&nbsp;Input(&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&amp;m,int&nbsp;&nbsp;&nbsp;&amp;n);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;看一下相应调用的汇编代码：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lea&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,[ebp-8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040106B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040106C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lea&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,[ebp-4]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040106F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@ILT+5(Input)&nbsp;&nbsp;&nbsp;(0040100a)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从以上调用Input函数的过程可以看出：在调用此函数之前，首先压栈ebp-8,然后压栈ebp-4,然后调用函数Input,在调用函数Input之后，没有相应的堆栈恢复工作(为其它的函数调用，所以我没有列出)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面再列出Input函数本身的汇编代码：(实际此函数不大，但做汇编例子还是大了些，大家可以只看前和后，中间代码与此例子无关)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;39:&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;WINAPI&nbsp;&nbsp;&nbsp;Input(&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&amp;m,int&nbsp;&nbsp;&nbsp;&amp;n)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;40:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebp&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebp,esp&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sub&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,48h&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esi&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edi&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lea&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edi,[ebp-48h]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040111C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,12h&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,0CCCCCCCCh&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rep&nbsp;&nbsp;&nbsp;stos&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[edi]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;41:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;s,i;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;42:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;43:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040112D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,eax&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040112F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;je&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+0C1h&nbsp;&nbsp;&nbsp;(004011d1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;44:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;45:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\nPlease&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;the&nbsp;&nbsp;&nbsp;first&nbsp;&nbsp;&nbsp;number&nbsp;&nbsp;&nbsp;m:");&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;&nbsp;"\nPlease&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;the&nbsp;&nbsp;&nbsp;first&nbsp;&nbsp;&nbsp;number&nbsp;&nbsp;&nbsp;m"...&nbsp;&nbsp;&nbsp;(004260b8)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040113A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;&nbsp;&nbsp;(00401530)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040113F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,4&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;46:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scanf("%d",&amp;m);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;&nbsp;"%d"&nbsp;&nbsp;&nbsp;(004260b4)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040114B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scanf&nbsp;&nbsp;&nbsp;(004015f0)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,8&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;47:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;48:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;m&lt;1&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;continue;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401156&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[edx],1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401159&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jge&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+4Dh&nbsp;&nbsp;&nbsp;(0040115d)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040115B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+18h&nbsp;&nbsp;&nbsp;(00401128)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;49:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\nPlease&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;the&nbsp;&nbsp;&nbsp;first&nbsp;&nbsp;&nbsp;number&nbsp;&nbsp;&nbsp;n:");&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040115D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;&nbsp;"\nPlease&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;the&nbsp;&nbsp;&nbsp;first&nbsp;&nbsp;&nbsp;number&nbsp;&nbsp;&nbsp;n"...&nbsp;&nbsp;&nbsp;(0042608c)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401162&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;&nbsp;&nbsp;(00401530)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,4&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;50:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scanf("%d",&amp;n);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040116A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+0Ch]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040116D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040116E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;&nbsp;"%d"&nbsp;&nbsp;&nbsp;(004260b4)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scanf&nbsp;&nbsp;&nbsp;(004015f0)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,8&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;51:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;52:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;n&lt;1&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;continue;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040117B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+0Ch]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040117E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ecx],1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jge&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+75h&nbsp;&nbsp;&nbsp;(00401185)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+18h&nbsp;&nbsp;&nbsp;(00401128)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;53:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;54:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=1,s=0;i&lt;=n;i++)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-8],1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040118C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-4],0&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401193&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+8Eh&nbsp;&nbsp;&nbsp;(0040119e)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;00401198&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edx,1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040119B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-8],edx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;0040119E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+0Ch]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011A1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011A4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[eax]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011A6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+0A3h&nbsp;&nbsp;&nbsp;(004011b3)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;55:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s=s+i;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011A8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-4]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011AB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011AE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-4],edx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011B1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+85h&nbsp;&nbsp;&nbsp;(00401195)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;56:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;&gt;=&nbsp;&nbsp;&nbsp;s&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011B3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp+8]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011B6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[eax]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011B8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecx,dword&nbsp;&nbsp;&nbsp;ptr&nbsp;&nbsp;&nbsp;[ebp-4]&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011BB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+0AFh&nbsp;&nbsp;&nbsp;(004011bf)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;57:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011BD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+0C1h&nbsp;&nbsp;&nbsp;(004011d1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;58:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;59:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;&lt;&nbsp;&nbsp;&nbsp;n*(n+1)/2,Please&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;again!\n");&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011BF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;&lt;&nbsp;&nbsp;&nbsp;n*(n+1)/2,Please&nbsp;&nbsp;&nbsp;input&nbsp;&nbsp;&nbsp;agai"...&nbsp;&nbsp;&nbsp;(00426060)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011C4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;&nbsp;&nbsp;(00401530)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011C9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,4&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;60:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input+18h&nbsp;&nbsp;&nbsp;(00401128)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;61:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;62:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;edi&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esi&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,48h&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebp,esp&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011D9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__chkesp&nbsp;&nbsp;&nbsp;(004015b0)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011DE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;esp,ebp&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011E0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ebp&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;004011E1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;最后，我们看到在函数末尾部分，有ret&nbsp;&nbsp;&nbsp;8，明显是恢复堆栈，由于在32位C++中，变量地址为4个字节(int也为4个字节)，所以弹栈两个地址即8个字节。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;由此可以看出：在主调用函数中负责压栈，在被调用函数中负责恢复堆栈。因此不能实现变参函数，因为被调函数不能事先知道弹栈数量，但在主调函数中是可以做到的，因为参数数量由主调函数确定。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;下面再看一下，ebp-8和ebp-4这两个地址实际存储的是什么值，ebp-8地址存储的是n&nbsp;&nbsp;&nbsp;的值，ebp&nbsp;&nbsp;&nbsp;-4存储的是m的值。说明也是从右到左压栈,进行参数传递。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;总结：在主调用函数中负责压栈，在被调用函数中负责弹出堆栈中的参数，并且负责恢复堆栈。因此不能实现变参函数，参数传递是从右到左。另外，命名修饰方法是在函数前加一个下划线(_)，在函数名后有符号(@)，在@后面紧跟参数列表中的参数所占字节数(10进制)，如：void&nbsp;&nbsp;&nbsp;Input(int&nbsp;&nbsp;&nbsp;&amp;m,int&nbsp;&nbsp;&nbsp;&amp;n),被修饰成：_Input@8&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于大多数api函数以及窗口消息处理函数皆用&nbsp;&nbsp;&nbsp;CALLBACK&nbsp;&nbsp;&nbsp;,所以调用前，主调函数会先压栈，然后api函数自己恢复堆栈。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;edx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;edi&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;eax&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;ebx&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;getdlgitemtexta&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;你可以想一下，这几个寄存器中存的都是什么？&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;参考：msdn&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;例子为在VC6.0下debug模式下的Win32&nbsp;&nbsp;&nbsp;Console反汇编代码。<br>类似的关键字还有_stdcall,如果用了_stdcall而不是_cdecl，那么清理工作由函数自己完成。 <br><br>_cdecl一般用于参数数量不确定的函数，因为这样的函数在调用之前不知道参数的长度，所以函数自身无法完成清理工作，例如printf()函数、scanf()函数等。<br><span id=CommnetList1_CommnetList1_rpCommentList__ctl1_lblContent>cdel:从右向左传参数,调用者清栈<br>pascal:从左向右传参数,被调用者清栈<br>stdcall:从右向左传参数,被调用者清栈<br>stdcall是cdel和pascal的结合!<br></span></div>
<img src ="http://www.cppblog.com/pwqonline/aggbug/67380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-11-20 14:42 <a href="http://www.cppblog.com/pwqonline/archive/2008/11/20/67380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADO数据库</title><link>http://www.cppblog.com/pwqonline/archive/2008/09/26/62816.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Fri, 26 Sep 2008 06:41:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/09/26/62816.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/62816.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/09/26/62816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/62816.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/62816.html</trackback:ping><description><![CDATA[在用ADO以前，一定得让你的程序知道去哪里找ADO。在stdafx.h文件里，需要加上 <br>下面的代码： <br>#import "c:\program files\common files\system\ado\msado15.dll" no_namespace <br>s rename("EOF", "adoEOF") <br>这行代码的作用是，告诉编译器去哪里找ADO的库文件(可能在你的机器上路径有所 <br>不同)，然后说明不用namespace，并且将 EOF 更名为 adoEOF(如果不这样干，很有可能 <br>会碰到常量冲突)。 <br>只要加了这句话，准备工作就全干完了，很简单是吗？不用包含任何头文件，不用 <br>为link指定任何lib文件，我也觉得有点神奇。//shrug <br><br>_ConnectionPtr, _CommandPtr, 和 _RecordsetPtr (本文中未提及 _CommandPtr)： <br>ADO，和 CDAODatabase、CDatabase 非常相似，也分这么几块，不同的是，ADO 以 <br>COM 为基础，这几块都是标准的COM组件，而 CDatabase 等等则是 MFC 类。有一点必 <br>须提请注意，要学习ADO编程，学点COM是不可避免的了，不过这是件好事，现在如果不 <br>会一点COM、OLE什么的，估计很难适应Windows编程的形势。ADO里面的三个组成部份就 <br>是三个COM组件：Connection、Command、Recordset。(还有两个暂时用不上的:) <br>Connection用于建立数据库连接，执行不返回任何结果集的SQL语句。 <br>Command用于返回结果集，并提供简单的方法执行存储过程或者任何返回结果集的S <br>QL语句。 <br>Recordset就是结果集，可进行数据的存取、滚动操作。 <br>如果给Command和Recordset正确的Connection string，而不是一个Connection对象 <br>的指针，它们一样可以打开记录集，这种情况适用于单数据库操作。当程序里需要频繁 <br>进行数据库操作时，最好还是预先定义一个Connection对象，用它连接数据库，而用Re <br>cordset处理数据。本文中将大量讨论这两个对象。 <br>_ConnectionPtr是一个Connection的接口，与CDatabase和CDAODatabase类似，实际 <br>工作原理也差不多。在程序里创建它的实例，通过某个OLE DB provider指向一个数据源 <br>，并开启连接。下面的代码是CDAODatabase和_ConnectionPtr的开启实例： <br><br><br>DAO: <br>CDaoDatabase MyDb = new CDaoDatabase(); <br>m_DaoServerDB.Open(NULL,FALSE,FALSE,"ODBC;DSN=SAMS_SVR;UID=admin;PWD=adm <br>in"); <br><br>ADO: <br>_ConnectionPtr MyDb; <br>MyDb.CreateInstance(__uuidof(Connection)); <br>MyDb-&gt;Open("DSN=SAMS_SVR;UID=admin;PWD=admin","","",-1); <br><br>_RecordsetPtr是记录集接口，与CDAORecordset类似。先看看它的开启方式与CDAO <br>Recordset有多么相似： <br><br>DAO: <br>CDaoRecordset MySet = new CDaoRecordset(MyDb); <br>MySet-&gt;Open(AFX_DAO_USE_DEFAULT_TYPE,"SELECT * FROM some_table"); <br><br>ADO: <br>_RecordsetPtr MySet; <br>MySet.CreateInstance(__uuidof(Recordset)); <br>MySet-&gt;Open("SELECT * FROM some_table", MyDb.GetInterfacePtr(), adOpenDy <br>namic, adLockOptimistic, adCmdText); <br><br>(译者注：请注意ADO在Open Recordset的时候，使用了MyDb.GetInterfacePtr()作 <br>为参数之一，当时我用了_ConnectionPtr, &amp;(_ConnectionPtr)都不行，原来要这么用， <br>真是不服不行。:() <br>ADO只是略微的麻烦一点，不过花这点功夫获得ADO的多多好处还是很值的。 <br>现在有了一个Connection和一个Recordset，下面该用这两个东东取点数据出来了。 <br>不妨先假定有一个名为m_List的Listbox，我们把数据取出来往里塞。 <br><br>DAO: <br>VARIANT *vFieldValue; <br>COleVariant covFieldValue; <br>CString Holder; <br>while(!MySet-&gt;IsEOF()) <br>{ <br>MySet-&gt;GetFieldValue("FIELD_1", covFieldValue); <br>vFieldValue = (LPVARIANT)covFieldValue; <br>if(vFieldValue-&gt;vt!-VT_NULL) <br>{ <br>Holder.Format("%s",vFieldValue-&gt;pbVal); <br>m_List.AddString(Holder); <br>} <br>MySet.MoveNext(); <br>} <br><br>ADO: <br>_variant_t Holder <br>while(!MySet-&gt;adoEOF) <br>{ <br>Holder = MySet-&gt;GetCollect("FIELD_1"); <br>if(Holder.vt!=VT_NULL) <br>m_List.AddString((char*)_bstr_t(Holder)); <br>MySet-&gt;MoveNext(); <br>} <br><br>注意：在微软所有的文档里，都没找到GetCollect方法。我找了所有的地方，也从 <br>没人提起过，在文档里的示例方式是这样： <br>Holder = MySet-&gt;GetFields-&gt;Field-&gt;(_variant_t(FieldNumber))-&gt;Value; <br>你喜欢哪一种呢，反正我是喜欢GetCollect。(译者注：鬼知道他从哪里搞到这个方 <br>法，难道是从MS自己人的程序里？I 服了 him。) <br><br>动态绑定 vs DFX(CRecordset 和 CDAORecordset的预先字段绑定，Data Field Exchan <br>ge)： <br>动态绑定即使用SQL语句动态构造结果字段，而不是象 CDAORecordset 里面用DFX去 <br>把所有原始字段映射成成员变量。动态绑定的例子： <br>SELECT (SUM(field_1) + SUM(field_2)) AS answer FROM some_table <br>如果用DFX，估计就得在程序里自己写了： <br>m_answer = m_field_1 + m_field2; <br>(译者注：尽管很多人喜欢 DFX 的字段预先绑定，宁可这么写代码，不过我很少用 <br>DFX，当然在 VB 里面更是从来不会用到，好象用得比较多的也就是在 Delphi 里面， <br>用起来还比较爽，大概是 MS 的文档里让我别用，而 Borland 的破文档里却没说吧。 <br>:-) <br>相比之下，动态绑定确有其优越的地方，减少了代码量，也让程序更小、更易维护 <br>。再说，这也是MS推荐的获取数据方式，更灵活，速度更快，更易维护，我们还能要求 <br>什么呢？ <br>对于大多数程序来说，都是创建一个全局的Connection，然后用Recordset来处理数 <br>据，如果Recordset数量很多，可以想象光是花费在DFX上面的代码就有多少。如果使用 <br>动态绑定，这些都省掉了。 <br><br>_variant_t 和 _bstr_t 到底是什么玩意？ <br>很不幸，我们喜爱的CString类在COM里用不了(CStringEx也一样)，因为COM必须设 <br>计成跨平台，它需要一种更普遍的方式来处理字符串以及其他数据。这就是VARIANT数据 <br>类型的来历，还有BSTR类型。VARIANT就是一个巨大的 union，包含了你能想得到的所有 <br>的数据类型，除了char*，不过还好，BSTR取代了char*。 <br>(译者注：似乎VARIANT是个很慢的东西，大家都不愿意使它，不过按我看来，情况 <br>没这么糟糕，union照理说不应该慢到哪去，要说慢，也是慢在给VARIANT分配地址空间 <br>上，这点在VC里面做得比VB要好 <br>这些东西看起来的确有点恐怖，不过实在用不着怕，等下面熟悉了这两个东西之后 <br>，你会很快喜欢的) <br>简单来说，_variant_t是一个类，包装了VARIANT数据类型，并允许我们简单的对之 <br>进行强制类型转换(相信大家都喜欢这个)，_bstr_t对BSTR干了同样的事情。在下面的例 <br>子里，你将看到怎么用GetCollect把数据取到VARIANT里，又怎么把它放到_bstr_t里， <br>最后强制转换成char*，以及把_variant_t强制转换成long、double或者其他一切东西： <br><br>_variant_t Holder; <br>// first get the VARIANT and put it into the _variant_t <br>Holder = MySet-&gt;GetCollect("FIELD_1"); <br>// now put it into a _bstr_t and cast it to a char* <br>m_List.AddString((char*)_bstr_t(Holder)); <br><br>对比一下没有用 _variant_t 和 _bstr_t 的代码： <br><br>COleVariant covFieldValuel <br>VARIANT vFieldValue <br>CString Holder; <br>MySet-&gt;GetFieldValue("FIELD_1", covFieldValue); <br>vFieldValue = (LPVARIANT)covFieldValue; <br>Holder.Format("%s",vFieldValue-&gt;pbVal); <br>m_List.AddString(Holder); <br><br>Update，Insert，Delete：<br>&nbsp;&nbsp;&nbsp;&nbsp; 当我进行Update，Insert，Delete操作时，通常我喜欢用Connection和Command对象<br>，原因是，用CString来构造SQL语句简单一些，然后直接用Connection.Execute就行了<br>。当然，用Recordset干这些也是可以的。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; Update方法有下面三种方法调用：<br>&nbsp;&nbsp;&nbsp;&nbsp; 1: 给某个Field对象(或某些个)的Value属性赋值，然后调用Update方法；<br>&nbsp;&nbsp;&nbsp;&nbsp; 2: 将字段名和字段值作为参数传给Update方法；<br>&nbsp;&nbsp;&nbsp;&nbsp; 3: 将字段名和字段值的数组作为参数传给Update方法。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; AddNew方法如下调用：<br>&nbsp;&nbsp;&nbsp;&nbsp; 1: 直接调用，然后同Update调用方法一；<br>&nbsp;&nbsp;&nbsp;&nbsp; 2: 将字段名数组、字段值数组作为参数传给AddNew方法。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; Delete方法最简单，直接调用就行了，删除当前记录！<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 做完这些事情，可能需要调用Requery方法才能看到效果。<br>&nbsp;&nbsp;&nbsp;&nbsp; 下面的示例代码需要我们创建一个简单的MFC Application，然后在CWinApp类里面<br>声明三个接口的对象：<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // Global ADO Objects<br>&nbsp;&nbsp;&nbsp;&nbsp; // connection<br>&nbsp;&nbsp;&nbsp;&nbsp; _ConnectionPtr m_pConnection;<br>&nbsp;&nbsp;&nbsp;&nbsp; _CommandPtr&nbsp;&nbsp; m_pCommand;<br>&nbsp;&nbsp;&nbsp;&nbsp; _RecordsetPtr m_pRecordset;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 在VC6里面有一点很有意思，如果敲 "m_pConnection."，你会看到一个方法和属性<br>列表，如果敲"m_pConnection-&gt;"，还会看到一个方法和属性列表，当然里面的内容完全<br>不同，因为你实际是在指向两个不同的东西。下面就是这两种混用的代码：<br><br>&nbsp;&nbsp;&nbsp;&nbsp; _ConnectionPtr MyDb;<br>&nbsp;&nbsp;&nbsp;&nbsp; MyDb.CreateInstance(__uuidof(Connection));<br>&nbsp;&nbsp;&nbsp;&nbsp; MyDb-&gt;Open("DSN=SAMS_SVR;UID=admin;PWD=admin","","",-1);<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 回到示例代码，在 application 的 InitInstance 方法里，我打开数据连接，指向我<br>机器上的一个数据库，你需要更改ConnectionString，使用你自己的ODBC数据源或指定<br>一个OLE DB provider。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // When we open the application we will open the ADO connection<br>&nbsp;&nbsp;&nbsp;&nbsp; m_pConnection.CreateInstance(__uuidof(Connection));<br>&nbsp;&nbsp;&nbsp;&nbsp; m_pConnection-&gt;Open("DSN=ADOTest","","",-1);<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 如果你打开about对话框，就会看到一个Listbox，还有一个叫button1的按钮，这里<br>面包含了 ADO 调用的核心代码。我创建了一个_RecordsetPtr接口的实例，打开我需要<br>的记录集，然后遍历所有记录，将它们塞到Listbox里去：<br><br>&nbsp;&nbsp;&nbsp;&nbsp; _variant_t TheValue;<br>&nbsp;&nbsp;&nbsp;&nbsp; theApp.m_pRecordset.CreateInstance(__uuidof(Recordset));<br>&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.m_pRecordset-&gt;Open("SELECT DISTINCT FLDESC FROM tblFALines",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.m_pConnection.GetInterfacePtr(),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adOpenDynamic,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adLockOptimistic,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adCmdText);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(!theApp.m_pRecordset-&gt;adoEOF)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TheValue = theApp.m_pRecordset-&gt;GetCollect("FLDESC");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(TheValue.vt!=VT_NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_List.AddString((char*)_bstr_t(TheValue));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.m_pRecordset-&gt;MoveNext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.m_pRecordset-&gt;Close();<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; catch(_com_error *e)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString Error = e-&gt;ErrorMessage();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(e-&gt;ErrorMessage());<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; catch(...)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox("Whoa this is bad");<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 记得一定要用try和catch，否则ADO调用错误有可能使你的程序崩溃，一定要随时记<br>得捕捉_com_error例外以及其它错误。<br>&nbsp;&nbsp;&nbsp;&nbsp; 我尽可能的使代码简单，所以省略了很多细节，尤其是忽略了很多好的编程习惯(比<br>如检查大多数COM方法都返回的HRESULT值)。本文的目的是想说，ADO并没什么难的，CO<br>M也一样，而不是想表现ADO能做的所有事情。我甚至都没仔细想过ADO能为你带来什么，<br>不过我肯定一点，那就是ADO比DAO、RDO更快、更容易使用、并且功能强大得多。看看本<br>站点其它的文章，你就会知道，通过ADO调用存储过程有多么容易！<br>&nbsp;&nbsp;&nbsp;&nbsp; 最后，我想向大家推荐两本书，其中有一本是完全免费的，在www.informit.com可<br>以找到电子版，另一本必须得付钱买了，不过我还是推荐两本都买，除非你家浴池里、<br>床头边也放了计算机。 :)<br>&nbsp;&nbsp;&nbsp;&nbsp; 免费的那本是&lt;Learn Database Programming with Visual C++ in 21 days&gt;。哦，<br>我知道你在想什么，我也知道那些'in 21 days'的书通常都很烂，而且当着其它程序员<br>的面买这样的书的确有点丢面子，并且还很不好意思把这样的书摆在书架上显眼的位置<br>。不过这一本绝对是个例外！里面的内容简直太棒了！<br>&nbsp;&nbsp;&nbsp;&nbsp; 要花钱的那本是&lt;ADO 2.0&gt;，由WROC出版... (译者注：细节就省了吧，反正我们也<br>不会花美元去买英文书)。<br><br>
<img src ="http://www.cppblog.com/pwqonline/aggbug/62816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-09-26 14:41 <a href="http://www.cppblog.com/pwqonline/archive/2008/09/26/62816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++字符串完全指南</title><link>http://www.cppblog.com/pwqonline/archive/2008/09/26/62811.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Fri, 26 Sep 2008 05:11:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/09/26/62811.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/62811.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/09/26/62811.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/62811.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/62811.html</trackback:ping><description><![CDATA[<p>字符串的表现形式各异，象TCHAR，std::string，BSTR等等，有时还会见到怪怪的用_tcs起头的宏。这个指南的目的就是说明各种字符串类型及其用途，并说明如何在必要时进行类型的相互转换。</p>
<p>在指南的第一部分，介绍三种字符编码格式。理解编码的工作原理是致为重要的。即使你已经知道字符串是一个字符的数组这样的概念，也请阅读本文，它会让你明白各种字符串类之间的关系。</p>
<p>指南的第二部分，将阐述各个字符串类，什么时候使用哪种字符串类，及其相互转换。</p>
<p>字符串基础 - ASCII, DBCS, Unicode <br>所有的字符串类都起源于C语言的字符串，而C语言字符串则是字符的数组。首先了解一下字符类型。有三种编码方式和三种字符类型。</p>
<p>第一种编码方式是单字节字符集，称之为SBCS，它的所有字符都只有一个字节的长度。ASCII码就是SBCS。SBCS字符串由一个零字节结尾。</p>
<p>第二种编码方式是多字节字符集，称之为MBCS，它包含的字符中有单字节长的字符，也有多字节长的字符。Windows用到的MBCS只有二种字符类型，单字节字符和双字节字符。因此Windows中用得最多的字符是双字节字符集，即DBCS，通常用它来代替MBCS。</p>
<p>在DBCS编码中，用一些保留值来指明该字符属于双字节字符。例如，Shift-JIS(通用日语)编码中，值0x81-0x9F 和 0xE0-0xFC 的意思是：&#8220;这是一个双字节字符，下一个字节是这个字符的一部分&#8221;。这样的值通常称为前导字节(lead byte)，总是大于0x7F。前导字节后面是跟随字节(trail byte)。DBCS的跟随字节可以是任何非零值。与SBCS一样，DBCS字符串也由一个零字节结尾。</p>
<p>第三种编码方式是Unicode。Unicode编码标准中的所有字符都是双字节长。有时也将Unicode称为宽字符集(wide characters)，因为它的字符比单字节字符更宽(使用更多内存)。注意，Unicode不是MBCS - 区别在于MBCS编码中的字符长度是不同的。Unicode字符串用二个零字节字符结尾(一个宽字符的零值编码)。</p>
<p>单字节字符集是拉丁字母，重音文字，用ASCII标准定义，用于DOS操作系统。双字节字符集用于东亚和中东语言。Unicode用于COM和Windows NT内部。</p>
<p>读者都很熟悉单字节字符集，它的数据类型是char。双字节字符集也使用char数据类型(双字节字符集中的许多古怪处之一)。Unicode字符集用wchar_t数据类型。Unicode字符串用L前缀起头，如：</p>
<p>wchar_t wch = L'1';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 2 个字节, 0x0031</p>
<p>wchar_t* wsz = L"Hello"; // 12 个字节, 6 个宽字符</p>
<p>字符串的存储 <br>单字节字符串顺序存放各个字符，并用零字节表示字符串结尾。例如，字符串"Bob"的存储格式为：</p>
<p>&#160;</p>
<p>Unicode编码中，L"Bob"的存储格式为：</p>
<p>&#160;</p>
<p>用0x0000 (Unicode的零编码)结束字符串。</p>
<p>DBCS 看上去有点象SBCS。以后我们会看到在串处理和指针使用上是有微妙差别的。字符串"日本语" (nihongo) 的存储格式如下(用LB和TB分别表示前导字节和跟随字节)：</p>
<p>&#160;</p>
<p>注意，"ni"的值不是WORD值0xFA93。值93和FA顺序组合编码为字符"ni"。(在高位优先CPU中，存放顺序正如上所述)。</p>
<p>字符串处理函数 <br>C语言字符串处理函数，如strcpy(), sprintf(), atol()等只能用于单字节字符串。在标准库中有只用于Unicode字符串的函数，如wcscpy(), swprintf(), _wtol()。</p>
<p>微软在C运行库(CRT)中加入了对DBCS字符串的支持。对应于strxxx()函数，DBCS使用_mbsxxx()函数。在处理DBCS字符串(如日语，中文，或其它DBCS)时，就要用_mbsxxx()函数。这些函数也能用于处理SBCS字符串(因为DBCS字符串可能就只含有单字节字符)。</p>
<p>现在用一个示例来说明字符串处理函数的不同。如有Unicode字符串L"Bob"：</p>
<p>&#160;</p>
<p>x86 CPU的排列顺序是低位优先(little-endian)的，值0x0042的存储顺序为42 00。这时如用strlen()函数求字符串的长度就发生问题。函数找到第一个字节42，然后是00，意味着字符串结尾，于是返回1。反之，用wcslen()函数求"Bob"的长度更糟糕。wcslen()首先找到0x6F42，然后是0x0062，以后就在内存缓冲内不断地寻找00 00直至发生一般性保护错(GPF)。</p>
<p>strxxx()及其对应的_mbsxxx()究竟是如何运作的？二者之间的不同是非常重要的，直接影响到正确遍历DBCS字符串的方法。下面先介绍字符串遍历，然后再回来讨论strxxx()和 _mbsxxx()。</p>
<p>&#160;</p>
<p>&#160;</p>
<p>字符串遍历 <br>我们中的大多数人都是从SBCS成长过来的，都习惯于用指针的 ++ 和 -- 操作符来遍历字符串，有时也使用数组来处理字符串中的字符。这二种方法对于SBCS 和 Unicode 字符串的操作都是正确无误的，因为二者的字符都是等长的，编译器能够的正确返回我们寻求的字符位置。</p>
<p>但对于DBCS字符串就不能这样了。用指针访问DBCS字符串有二个原则，打破这二个原则就会造成错误。</p>
<p>1. 不可使用 ++ 算子，除非每次都检查是否为前导字节。</p>
<p>2. 绝不可使用 -- 算子来向后遍历。</p>
<p>先说明原则2，因为很容易找到一个非人为的示例。假设，有一个配制文件，程序启动时要从安装路径读取该文件，如：C:\Program Files\MyCoolApp\config.bin。文件本身是正常的。</p>
<p>假设用以下代码来配制文件名：</p>
<p>bool GetConfigFileName ( char* pszName, size_t nBuffSize ) <br>{ <br>char szConfigFilename[MAX_PATH]; <br>&nbsp;&nbsp;&nbsp; // 这里从注册表读取文件的安装路径，假设一切正常。 <br>&nbsp;&nbsp;&nbsp; // 如果路径末尾没有反斜线，就加上反斜线。 <br>&nbsp;&nbsp;&nbsp; // 首先，用指针指向结尾零： <br>char* pLastChar = strchr ( szConfigFilename, '\0' ); <br>&nbsp;&nbsp;&nbsp; // 然后向后退一个字符： <br>&nbsp;&nbsp;&nbsp; pLastChar--;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; if ( *pLastChar != '\\' ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat ( szConfigFilename, "\\" ); <br>&nbsp;&nbsp;&nbsp; // 加上文件名： <br>&nbsp;&nbsp;&nbsp; strcat ( szConfigFilename, "config.bin" ); <br>&nbsp;&nbsp;&nbsp; // 如果字符串长度足够，返回文件名： <br>&nbsp;&nbsp;&nbsp; if ( strlen ( szConfigFilename ) &gt;= nBuffSize ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false; <br>&nbsp;&nbsp;&nbsp; else <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy ( pszName, szConfigFilename ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>} <br>这段代码的保护性是很强的，但用到DBCS字符串还是会出错。假如文件的安装路径用日语表达：C:\ヨウユソ，该字符串的内存表达为：</p>
<p>&#160;</p>
<p>这时用上面的GetConfigFileName()函数来检查文件路径末尾是否含有反斜线就会出错，得到错误的文件名。</p>
<p>错在哪里？注意上面的二个十六进制值0x5C(蓝色)。前面的0x5C是字符"\"，后面则是字符值83 5C，代表字符"ソ"。可是函数把它误认为反斜线了。</p>
<p>正确的方法是用DBCS函数将指针指向恰当的字符位置，如下所示：</p>
<p>bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize ) <br>{ <br>char szConfigFilename[MAX_PATH]; <br>&nbsp;&nbsp;&nbsp; // 这里从注册表读取文件的安装路径，假设一切正常。 <br>&nbsp;&nbsp;&nbsp; // 如果路径末尾没有反斜线，就加上反斜线。 <br>&nbsp;&nbsp;&nbsp; // 首先，用指针指向结尾零： <br>char* pLastChar = _mbschr ( szConfigFilename, '\0' ); <br>&nbsp;&nbsp;&nbsp; // 然后向后退一个双字节字符： <br>&nbsp;&nbsp;&nbsp; pLastChar = CharPrev ( szConfigFilename, pLastChar ); <br>&nbsp;&nbsp;&nbsp; if ( *pLastChar != '\\' ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _mbscat ( szConfigFilename, "\\" ); <br>&nbsp;&nbsp;&nbsp; // 加上文件名： <br>&nbsp;&nbsp;&nbsp; _mbscat ( szConfigFilename, "config.bin" ); <br>&nbsp;&nbsp;&nbsp; // 如果字符串长度足够，返回文件名： <br>&nbsp;&nbsp;&nbsp; if ( _mbslen ( szInstallDir ) &gt;= nBuffSize ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false; <br>&nbsp;&nbsp;&nbsp; else <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _mbscpy ( pszName, szConfigFilename ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>} <br>这个改进的函数用CharPrev() API 函数将指针pLastChar向后移动一个字符。如果字符串末尾的字符是双字节字符，就向后移动2个字节。这时返回的结果是正确的，因为不会将字符误判为反斜线。</p>
<p>&#160;</p>
<p>现在可以想像到第一原则了。例如，要遍历字符串寻找字符":"，如果不使用CharNext()函数而使用++算子，当跟随字节值恰好也是":"时就会出错。</p>
<p>与原则2相关的是数组下标的使用：</p>
<p>　2a. 绝不可在字符串数组中使用递减下标。</p>
<p>出错原因与原则2相同。例如，设置指针pLastChar为：</p>
<p>char* pLastChar = &amp;szConfigFilename [strlen(szConfigFilename) - 1]; <br>结果与原则2的出错一样。下标减1就是指针向后移动一个字节，不符原则2。</p>
<p>再谈strxxx() 与_mbsxxx() <br>现在可以清楚为什么要用 _mbsxxx() 函数了。strxxx() 函数不认识DBCS字符而 _mbsxxx()认识。如果调用strrchr("C:\\", '\\')函数可能会出错，但 _mbsrchr()认识双字节字符，所以能返回指向最后出现反斜线字符的指针位置。</p>
<p>最后提一下strxxx() 和 _mbsxxx() 函数族中的字符串长度测量函数，它们都返回字符串的字节数。如果字符串含有3个双字节字符，_mbslen()将返回6。而Unicode的函数返回的是wchar_ts的数量，如wcslen(L"Bob") 返回3</p>
<p>Win32 API中的MBCS 和 Unicode <br>API的二个字符集 <br>也许你没有注意到，Win32的API和消息中的字符串处理函数有二种，一种为MCBS字符串，另一种为Unicode字符串。例如，Win32中没有SetWindowText()这样的接口，而是用SetWindowTextA()和 SetWindowTextW()函数。后缀A (表示ANSI)指明是MBCS函数，后缀W(表示宽字符)指明是Unicode函数。</p>
<p>编写Windows程序时，可以选择用MBCS或Unicode API接口函数。用VC AppWizards向导时，如果不修改预处理器设置，缺省使用的是MBCS函数。但是在API接口中没有SetWindowText()函数，该如何调用呢？实际上，在winuser.h头文件中做了以下定义：</p>
<p>BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString ); <br>BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString ); <br>#ifdef UNICODE <br>　#define SetWindowText SetWindowTextW <br>#else <br>　#define SetWindowText SetWindowTextA <br>#endif <br>编写MBCS应用时，不必定义UNICODE，预处理为：</p>
<p>#define SetWindowText SetWindowTextA <br>然后将SetWindowText()处理为真正的API接口函数SetWindowTextA() (如果愿意的话，可以直接调用SetWindowTextA() 或SetWindowTextW()函数，不过很少有此需要)。</p>
<p>如果要将缺省应用接口改为Unicode，就到预处理设置的预处理标记中去掉 _MBCS标记，加入UNICODE 和 _UNICODE (二个标记都要加入，不同的头文件使用不同的标记)。不过，这时要处理普通字符串反而会遇到问题。如有代码：</p>
<p>HWND hwnd = GetSomeWindowHandle(); <br>char szNewText[] = "we love Bob!"; <br>SetWindowText ( hwnd, szNewText ); <br>编译器将"SetWindowText"置换为"SetWindowTextW"后，代码变为：</p>
<p>HWND hwnd = GetSomeWindowHandle(); <br>char szNewText[] = "we love Bob!"; <br>SetWindowTextW ( hwnd, szNewText ); <br>看出问题了吧，这里用一个Unicode字符串处理函数来处理单字节字符串。</p>
<p>第一种解决办法是使用宏定义： <br>HWND hwnd = GetSomeWindowHandle(); <br>#ifdef UNICODE <br>　wchar_t szNewText[] = L"we love Bob!"; <br>#else <br>　char szNewText[] = "we love Bob!"; <br>#endif <br>SetWindowText ( hwnd, szNewText ); <br>要对每一个字符串都做这样的宏定义显然是令人头痛的。所以用TCHAR来解决这个问题：</p>
<p>TCHAR的救火角色 <br>TCHAR 是一种字符类型，适用于MBCS 和 Unicode二种编码。程序中也不必到处使用宏定义。</p>
<p>TCHAR的宏定义如下：</p>
<p>#ifdef UNICODE <br>　typedef wchar_t TCHAR; <br>#else <br>　typedef char TCHAR; <br>#endif <br>所以，TCHAR中在MBCS程序中是char类型，在Unicode中是 wchar_t 类型。</p>
<p>对于Unicode字符串，还有个 _T() 宏，用于解决 L 前缀：</p>
<p>#ifdef UNICODE <br>　#define _T(x) L##x <br>#else <br>　#define _T(x) x <br>#endif <br>## 是预处理算子，将二个变量粘贴在一起。不管什么时候都对字符串用 _T 宏处理，这样就可以在Unicode编码中给字符串加上L前缀，如：</p>
<p>TCHAR szNewText[] = _T("we love Bob!"); <br>SetWindowTextA/W 函数族中还有其它隐藏的宏可以用来代替strxxx() 和 _mbsxxx() 字符串函数。例如，可以用 _tcsrchr 宏取代strrchr()，_mbsrchr()，或 wcsrchr()函数。_tcsrchr 根据编码标记为_MBCS 或 UNICODE，将右式函数做相应的扩展处理。宏定义方法类似于SetWindowText。</p>
<p>不止strxxx()函数族中有TCHAR宏定义，其它一些函数中也有。例如，_stprintf (取代sprintf()和swprintf())，和 _tfopen (取代fopen() 和 _wfopen())。MSDN的全部宏定义在"Generic-Text Routine Mappings"栏目下。</p>
<p>String 和 TCHAR 类型定义 <br>Win32 API 文件中列出的函数名都是通用名(如"SetWindowText")，所有的字符串都按照TCHAR类型处理。(只有XP除外，XP只使用Unicode类型)。下面是MSDN给出的常用类型定义：</p>
<p>类型 <br>MBCS 编码中的意义 <br>Unicode 编码中的意义 <br><br>WCHAR <br>wchar_t <br>wchar_t <br><br>LPSTR <br>zero-terminated string of char (char*) <br>zero-terminated string of char (char*) <br><br>LPCSTR <br>constant zero-terminated string of char (constchar*) <br>constant zero-terminated string of char (constchar*) <br><br>LPWSTR <br>zero-terminated Unicode string (wchar_t*) <br>zero-terminated Unicode string (wchar_t*) <br><br>LPCWSTR <br>constant zero-terminated Unicode string (const wchar_t*) <br>constant zero-terminated Unicode string (const wchar_t*) <br><br>TCHAR <br>char <br>wchar_t <br><br>LPTSTR <br>zero-terminated string of TCHAR (TCHAR*) <br>zero-terminated string of TCHAR (TCHAR*) <br><br>LPCTSTR <br>constant zero-terminated string of TCHAR (const TCHAR*) <br>constant zero-terminated string of TCHAR (const TCHAR*) <br></p>
<p>何时使用TCHAR 和Unicode <br>可能会有疑问：&#8220;为什么要用Unicode？我一直用的都是普通字符串。&#8221;</p>
<p>在三种情况下要用到Unicode：</p>
<p>程序只运行于Windows NT。 <br>处理的字符串长于MAX_PATH定义的字符数。 <br>程序用于Windows XP中的新接口，那里没有A/W版本之分。 <br>大部分Unicode API不可用于Windows 9x。所以如果程序要在Windows 9x上运行的话，要强制使用MBCS API (微软推出一个可运行于Windows 9x的新库，叫做Microsoft Layer for Unicode。但我没有试用过，无法说明它的好坏)。相反，NT内部全部使用Unicode编码，使用Unicode API可以加速程序运行。每当将字符串处理为MBCS API时，操作系统都会将字符串转换为Unicode并调用相应的Unicode API 函数。对于返回的字符串，操作系统要做同样的转换。尽管这些转换经过了高度优化，模块尽可能地压缩到最小，但毕竟会影响到程序的运行速度。</p>
<p>NT允许使用超长文件名(长于MAX_PATH 定义的260)，但只限于Unicode API使用。Unicode API的另外一个优点是程序能够自动处理输入的文字语言。用户可以混合输入英文，中文和日文作为文件名。不必使用其它代码来处理，都按照Unicode编码方式处理。</p>
<p>最后，作为Windows 9x的结局，微软似乎抛弃了MBCS API。例如，SetWindowTheme() 接口函数的二个参数只支持Unicode编码。使用Unicode编码省却了MBCS与Unicode之间的转换过程。</p>
<p>如果程序中还没有使用到Unicode编码，要坚持使用TCHAR和相应的宏。这样不但可以长期保持程序中DBCS编码的安全性，也利于将来扩展使用到Unicode编码。那时只要改变预处理中的设置即可！</p>
<p>各种字符串类（一） </p>
<p>前言</p>
<p>C语言的字符串容易出错，难以管理，并且往往是黑客到处寻找的目标。于是，出现了许多字符串包装类。可惜，人们并不很清楚什么情况下该用哪个类，也不清楚如何将C语言字符串转换到包装类。</p>
<p>本文涉及到Win32 API，MFC，STL，WTL和Visual C++运行库中使用到的所有的字符串类型。说明各个类的用法，如何构造对象，如何进行类转换等等。Nish为本文提供了Visual C++ 7的managed string 类的用法。</p>
<p>阅读本文之前，应完全理解本指南第一部分中阐述的字符类型和编码。</p>
<p>字符串类的首要原则：</p>
<p>不要随便使用类型强制转换，除非转换的类型是明确由文档规定的。</p>
<p>之所以撰写字符串指南这二篇文章，是因为常有人问到如何将X类型的字符串转换到Z类型。提问者使用了强制类型转换(cast)，但不知道为什么不能转换成功。各种各样的字符串类型，特别是BSTR，在任何场合都不是三言二语可以讲清的。因此，我以为这些提问者是想让强制类型转换来处理一切。</p>
<p>除非明确规定了转换算子，不要将任何其它类型数据强制转换为string。一个字符串不能用强制类型转换到string类。例如：</p>
<p>void SomeFunc ( LPCWSTR widestr );main(){ SomeFunc ( (LPCWSTR) "C:\\foo.txt" ); // 错！} <br>这段代码100%错误。它可以通过编译，因为类型强制转换超越了编译器的类型检验。但是，能够通过编译，并不证明代码是正确的。</p>
<p>下面，我将指出什么时候用类型强制转换是合理的。 <br>C语言字符串与类型定义</p>
<p>如指南的第一部分所述，Windows API定义了TCHAR术语。它可用于MBCS或Unicode编码字符，取决于预处理设置为_MBCS 或 _UNICODE标记。关于TCHAR的详细说明请阅指南的第一部分。为便于叙述，下面给出字符类型定义：</p>
<p>Type <br>Meaning <br><br>WCHAR <br>Unicode character (wchar_t) <br><br>TCHAR <br>MBCS or Unicode character, depending on preprocessor settings <br><br>LPSTR <br>string of char (char*) <br><br>LPCSTR <br>constant string of char (constchar*) <br><br>LPWSTR <br>string of WCHAR (WCHAR*) <br><br>LPCWSTR <br>constant string of WCHAR (const WCHAR*) <br><br>LPTSTR <br>string of TCHAR (TCHAR*) <br><br>LPCTSTR <br>constant string of TCHAR (const TCHAR*) <br></p>
<p>另外还有一个字符类型OLECHAR。这是一种对象链接与嵌入的数据类型(比如嵌入Word文档)。这个类型通常定义为wchar_t。如果将预处理设置定义为OLE2ANSI，OLECHAR将被定义为char类型。现在已经不再定义OLE2ANSI(它只在MFC 3以前版本中使用)，所以我将OLECHAR作为Unicode字符处理。</p>
<p>下面是与OLECHAR相关的类型定义：</p>
<p>Type <br>Meaning <br><br>OLECHAR <br>Unicode character (wchar_t) <br><br>LPOLESTR <br>string of OLECHAR (OLECHAR*) <br><br>LPCOLESTR <br>constant string of OLECHAR (const OLECHAR*) <br></p>
<p>还有以下二个宏让相同的代码能够适用于MBCS和Unicode编码：</p>
<p>Type <br>Meaning <br><br>_T(x) <br>Prepends L to the literal in Unicode builds. <br><br>OLESTR(x) <br>Prepends L to the literal to make it an LPCOLESTR. <br></p>
<p>宏_T有几种形式，功能都相同。如： -- TEXT, _TEXT, __TEXT, 和 __T这四种宏的功能相同。</p>
<p>&#160;</p>
<p>COM中的字符串 - BSTR 与 VARIANT</p>
<p>许多COM接口使用BSTR声明字符串。BSTR有一些缺陷，所以我在这里让它独立成章。</p>
<p>BSTR是Pascal类型字符串(字符串长度值显式地与数据存放在一起)和C类型字符串(字符串长度必须通过寻找到结尾零字符来计算)的混合型字符串。BSTR属于Unicode字符串，字符串中预置了字符串长度值，并且用一个零字符来结尾。下面是一个"Bob"的BSTR字符串：</p>
<p>&#160;</p>
<p>注意，字符串长度值是一个DWORD类型值，给出字符串的字节长度，但不包括结尾零。在上例，"Bob"含有3个Unicode字符(不计结尾零)，6个字节长。因为明确给出了字符串长度，所以当BSTR数据在不同的处理器和计算机之间传送时，COM库能够知道应该传送的数据量。</p>
<p>附带说一下，BSTR可以包含任何数据块，不单是字符。它甚至可以包容内嵌零字符数据。这些不在本文讨论范围。</p>
<p>C++中的BSTR变量其实就是指向字符串首字符的指针。BSTR是这样定义的：</p>
<p>typedef OLECHAR* BSTR; <br>这个定义很糟糕，因为事实上BSTR与Unicode字符串不一样。有了这个类型定义，就越过了类型检查，可以混合使用LPOLESTR和BSTR。向一个需要LPCOLESTR (或 LPCWSTR)类型数据的函数传递BSTR数据是安全的，反之则不然。所以要清楚了解函数所需的字符串类型，并向函数传递正确类型的字符串。</p>
<p>要知道为什么向一个需要BSTR类型数据的函数传递LPCWSTR类型数据是不安全的，就别忘了BSTR必须在字符串开头的四个字节保留字符串长度值。但LPCWSTR字符串中没有这个值。当其它的处理过程(如Word)要寻找BSTR的长度值时就会找到一堆垃圾或堆栈中的其它数据或其它随机数据。这就导致方法失效，当长度值太大时将导致崩溃。</p>
<p>许多应用接口都使用BSTR，但都用到二个最重要的函数来构造和析构BSTR。就是SysAllocString()和SysFreeString()函数。SysAllocString()将Unicode字符串拷贝到BSTR，SysFreeString()释放BSTR。示例如下：</p>
<p>BSTR bstr = NULL;bstr = SysAllocString ( L"Hi Bob!" );if ( NULL == bstr ) // 内存溢出 // 这里使用bstrSysFreeString ( bstr ); <br>当然，各种BSTR包装类都会小心地管理内存。</p>
<p>自动接口中的另一个数据类型是VARIANT。它用于在无类型语言，诸如JScript，VBScript，以及Visual Basic，之间传递数据。VARIANT可以包容许多不用类型的数据，如long和IDispatch*。如果VARIANT包含一个字符串，这个字符串是BSTR类型。在下文的VARIANT包装类中我还会谈及更多的VARIANT。</p>
<p>_bstr_t </p>
<p>&#160;</p>
<p>字符串包装类</p>
<p>我已经说明了字符串的各种类型，现在讨论包装类。对于每个包装类，我都会说明它的对象构造过程和如何转换成C类型字符串指针。应用接口的调用，或构造另一个不同类型的字符串类，大多都要用到C类型指针。本文不涉及类的其它操作，如排序和比较等。</p>
<p>再强调一下，在完全了解转换结果之前不要随意使用强制类型转换。</p>
<p>CRT类 <br>_bstr_t</p>
<p>_bstr_t 是BSTR的完全包装类。实际上，它隐含了BSTR。它提供多种构造函数，能够处理隐含的C类型字符串。但它本身却不提供BSTR的处理机制，所以不能作为COM方法的输出参数[out]。如果要用到BSTR* 类型数据，用ATL的CComBSTR类更为方便。</p>
<p>_bstr_t 数据可以传递给需要BSTR数据的函数，但必须满足以下三个条件：</p>
<p>首先，_bstr_t 具有能够转换为wchar_t*类型数据的函数。</p>
<p>其次，根据BSTR定义，使得wchar_t* 和BSTR对于编译器来说是相同的。</p>
<p>第三，_bstr_t内部保留的指向内存数据块的指针 wchar_t* 要遵循BSTR格式。</p>
<p>满足这些条件，即使没有相应的BSTR转换文档，_bstr_t 也能正常工作。示例如下：</p>
<p>// 构造_bstr_t bs1 = "char string"; // 从LPCSTR构造 _bstr_t bs2 = L"wide char string"; // 从LPCWSTR构造_bstr_t bs3 = bs1; // 拷贝另一个 _bstr_t_variant_t v = "Bob";_bstr_t bs4 = v; // 从一个含有字符串的 _variant_t 构造// 数据萃取LPCSTR psz1 = bs1; // 自动转换到MBCS字符串LPCSTR psz2 = (LPCSTR) bs1; // cast OK, 同上LPCWSTR pwsz1 = bs1; // 返回内部的Unicode字符串LPCWSTR pwsz2 = (LPCWSTR) bs1; // cast OK, 同上BSTR bstr = bs1.copy(); // 拷贝bs1, 返回BSTR// ... SysFreeString ( bstr ); <br>注意，_bstr_t 也可以转换为char* 和 wchar_t*。这是个设计问题。虽然char* 和 wchar_t*不是常量指针，但不能用于修改字符串，因为可能会打破内部BSTR结构。</p>
<p>_variant_t <br>_variant_t </p>
<p>_variant_t 是VARIANT的完全包装类。它提供多种构造函数和数据转换函数。本文仅讨论与字符串有关的操作。</p>
<p>// 构造_variant_t v1 = "char string"; // 从LPCSTR 构造_variant_t v2 = L"wide char string"; // 从LPCWSTR 构造_bstr_t bs1 = "Bob";_variant_t v3 = bs1; // 拷贝一个 _bstr_t 对象// 数据萃取_bstr_t bs2 = v1; // 从VARIANT中提取BSTR_bstr_t bs3 = (_bstr_t) v1; // cast OK, 同上 <br>注意，_variant_t 方法在转换失败时会抛出异常，所以要准备用catch 捕捉_com_error异常。</p>
<p>另外要注意 _variant_t 不能直接转换成MBCS字符串。要建立一个过渡的_bstr_t 变量，用其它提供转换Unicode到MBCS的类函数，或ATL转换宏来转换。</p>
<p>与_bstr_t 不同，_variant_t 数据可以作为参数直接传送给COM方法。_variant_t 继承了VARIANT类型，所以在需要使用VARIANT的地方使用_variant_t 是C++语言规则允许的。</p>
<p>STL类 </p>
<p>&#160;</p>
<p>STL类 <br>STL只有一个字符串类，即basic_string。basic_string管理一个零结尾的字符数组。字符类型由模板参数决定。通常，basic_string被处理为不透明对象。可以获得一个只读指针来访问缓冲区，但写操作都是由basic_string的成员函数进行的。</p>
<p>basic_string预定义了二个特例：string，含有char类型字符；which，含有wchar_t类型字符。没有内建的TCHAR特例，可用下面的代码实现：</p>
<p>// 特例化typedef basic_string tstring; // TCHAR字符串// 构造string str = "char string"; // 从LPCSTR构造wstring wstr = L"wide char string"; // 从LPCWSTR构造tstring tstr = _T("TCHAR string"); // 从LPCTSTR构造// 数据萃取LPCSTR psz = str.c_str(); // 指向str缓冲区的只读指针LPCWSTR pwsz = wstr.c_str(); // 指向wstr缓冲区的只读指针LPCTSTR ptsz = tstr.c_str(); // 指向tstr缓冲区的只读指针</p>
<p>与_bstr_t 不同，basic_string不能在字符集之间进行转换。但是如果一个构造函数接受相应的字符类型，可以将由c_str()返回的指针传递给这个构造函数。例如：</p>
<p>// 从basic_string构造_bstr_t _bstr_t bs1 = str.c_str(); // 从LPCSTR构造 _bstr_t_bstr_t bs2 = wstr.c_str(); // 从LPCWSTR构造 _bstr_t <br>ATL类 <br>CComBSTR <br>CComBSTR 是ATL的BSTR包装类。某些情况下比_bstr_t 更有用。最主要的是，CComBSTR允许操作隐含BSTR。就是说，传递一个CComBSTR对象给COM方法时，CComBSTR对象会自动管理BSTR内存。例如，要调用下面的接口函数：</p>
<p>// 简单接口struct IStuff : public IUnknown{ // 略去COM程序... STDMETHOD(SetText)(BSTR bsText); STDMETHOD(GetText)(BSTR* pbsText);}; <br>CComBSTR 有一个BSTR操作方法，能将BSTR直接传递给SetText()。还有一个引用操作(operator &amp;)方法，返回BSTR*，将BSTR*传递给需要它的有关函数。</p>
<p>CComBSTR bs1;CComBSTR bs2 = "new text";pStuff-&gt;GetText ( &amp;bs1 ); // ok, 取得内部BSTR地址 pStuff-&gt;SetText ( bs2 ); // ok, 调用BSTR转换 pStuff-&gt;SetText ( (BSTR) bs2 ); // cast ok, 同上 <br>CComVariant <br>CComBSTR有类似于 _bstr_t 的构造函数。但没有内建MBCS字符串的转换函数。可以调用ATL宏进行转换。</p>
<p>// 构造CComBSTR bs1 = "char string"; // 从LPCSTR构造CComBSTR bs2 = L"wide char string"; // 从LPCWSTR构造CComBSTR bs3 = bs1; // 拷贝CComBSTRCComBSTR bs4;bs4.LoadString ( IDS_SOME_STR ); // 从字符串表加载// 数据萃取BSTR bstr1 = bs1; // 返回内部BSTR，但不可修改！BSTR bstr2 = (BSTR) bs1; // cast ok, 同上BSTR bstr3 = bs1.Copy(); // 拷贝bs1, 返回BSTRBSTR bstr4;bstr4 = bs1.Detach(); // bs1不再管理它的BSTR// ...SysFreeString ( bstr3 );SysFreeString ( bstr4 ); <br>上面的最后一个示例用到了Detach()方法。该方法调用后，CComBSTR对象就不再管理它的BSTR或其相应内存。所以bstr4就必须调用SysFreeString()。</p>
<p>最后讨论一下引用操作符(operator &amp;)。它的超越使得有些STL集合(如list)不能直接使用CComBSTR。在集合上使用引用操作返回指向包容类的指针。但是在CComBSTR上使用引用操作，返回的是BSTR*，不是CComBSTR*。不过可以用ATL的CAdapt类来解决这个问题。例如，要建立一个CComBSTR的队列，可以声明为：</p>
<p>std::list&lt; CAdapt&gt; bstr_list; <br>CAdapt 提供集合所需的操作，是隐含于代码的。这时使用bstr_list 就象在操作一个CComBSTR队列。</p>
<p>CComVariant <br>CComVariant 是VARIANT的包装类。但与 _variant_t 不同，它的VARIANT不是隐含的，可以直接操作类里的VARIANT成员。CComVariant 提供多种构造函数和多类型操作。这里只介绍与字符串有关的操作。</p>
<p>// 构造CComVariant v1 = "char string"; // 从LPCSTR构造CComVariant v2 = L"wide char string"; // 从LPCWSTR构造CComBSTR bs1 = "BSTR bob";CComVariant v3 = (BSTR) bs1; // 从BSTR拷贝// 数据萃取CComBSTR bs2 = v1.bstrVal; // 从VARIANT提取BSTR <br>跟_variant_t 不同，CComVariant没有不同VARIANT类型之间的转换操作。必须直接操作VARIANT成员，并确定该VARIANT的类型无误。调用ChangeType()方法可将CComVariant数据转换为BSTR。</p>
<p>CComVariant v4 = ... // 从某种类型初始化 v4CComBSTR bs3;if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) )) bs3 = v4.bstrVal; <br>跟 _variant_t 一样，CComVariant不能直接转换为MBCS字符串。要建立一个过渡的_bstr_t 变量，用其它提供转换Unicode到MBCS的类函数，或ATL转换宏来转换。</p>
<p>ATL转换宏 </p>
<p>ATL转换宏 <br>ATL的字符串转换宏可以方便地转换不同编码的字符，用在函数中很有效。宏按照[source type]2[new type] 或 [source type]2C[new type]格式命名。后者转换为一个常量指针 (名字内含"C")。类型缩写如下：</p>
<p><br>　A：MBCS字符串，char* (A for ANSI) <br>　W：Unicode字符串，wchar_t* (W for wide) <br>　T：TCHAR字符串，TCHAR* <br>　OLE：OLECHAR字符串，OLECHAR* (实际等于W) <br>　BSTR：BSTR (只用于目的类型) <br>例如，W2A() 将Unicode字符串转换为MBCS字符串，T2CW()将TCHAR字符串转换为Unicode字符串常量。</p>
<p>要使用宏转换，程序中要包含atlconv.h头文件。可以在非ATL程序中使用宏转换，因为头文件不依赖其它的ATL，也不需要 _Module全局变量。如在函数中使用转换宏，在函数起始处先写上USES_CONVERSION宏。它表明某些局部变量由宏控制使用。</p>
<p>转换得到的结果字符串，只要不是BSTR，都存储在堆栈中。如果要在函数外使用这些字符串，就要将这些字符串拷贝到其它的字符串类。如果结果是BSTR，内存不会自动释放，因此必须将返回值分配给一个BSTR变量或BSTR的包装类，以避免内存泄露。</p>
<p>下面是若干宏转换示例：</p>
<p>// 带有字符串的函数：void Foo ( LPCWSTR wstr );void Bar ( BSTR bstr );// 返回字符串的函数：void Baz ( BSTR* pbstr );#include main(){using std::string;USES_CONVERSION; // 声明局部变量由宏控制使用// 示例1：送一个MBCS字符串到Foo()LPCSTR psz1 = "Bob";string str1 = "Bob";Foo ( A2CW(psz1) ); Foo ( A2CW(str1.c_str()) );// 示例2：将MBCS字符串和Unicode字符串送到Bar()LPCSTR psz2 = "Bob";LPCWSTR wsz = L"Bob";BSTR bs1;CComBSTR bs2;bs1 = A2BSTR(psz2); // 创建 BSTR bs2.Attach ( W2BSTR(wsz) ); // 同上，分配到CComBSTRBar ( bs1 ); Bar ( bs2 );SysFreeString ( bs1 ); // 释放bs1 // 不必释放bs2，由CComBSTR释放。// 示例3：转换由Baz()返回的BSTRBSTR bs3 = NULL;string str2;Baz ( &amp;bs3 ); // Baz() 填充bs3内容str2 = W2CA(bs3); // 转换为MBCS字符串 SysFreeString ( bs3 ); // 释放bs3} <br>可以看到，向一个需要某种类型参数的函数传递另一种类型的参数，用宏转换是非常方便的。</p>
<p>MFC类 <br>CString</p>
<p>MFC的CString含有TCHAR，它的实际字符类型取决于预处理标记的设置。通常，CString象STL字符串一样是不透明对象，只能用CString的方法来修改。CString比STL字符串更优越的是它的构造函数接受MBCS和Unicode字符串。并且可以转换为LPCTSTR，因此可以向接受LPCTSTR的函数直接传递CString对象，不必调用c_str()方法。</p>
<p>// 构造CString s1 = "char string"; // 从LPCSTR构造CString s2 = L"wide char string"; // 从LPCWSTR构造CString s3 ( ' ', 100 ); // 预分配100字节，填充空格CString s4 = "New window text";// 可以在LPCTSTR处使用CString：SetWindowText ( hwndSomeWindow, s4 );// 或者，显式地做强制类型转换：SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 ); <br>也可以从字符串表加载字符串。CString通过LoadString()来构造对象。用Format()方法可有选择地从字符串表读取一定格式的字符串。</p>
<p>// 从字符串表构造/加载CString s5 ( (LPCTSTR) IDS_SOME_STR ); // 从字符串表加载CString s6, s7;// 从字符串表加载 s6.LoadString ( IDS_SOME_STR );// 从字符串表加载打印格式的字符串 s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... ); <br>第一个构造函数看上去有点怪，但它的确是文档标定的字符串加载方式。</p>
<p>注意，CString只允许一种强制类型转换，即强制转换为LPCTSTR。强制转换为LPTSTR (非常量指针)是错误的。按照老习惯，将CString强制转换为LPTSTR只能伤害自己。有时在程序中没有发现出错，那只是碰巧。转换到非常量指针的正确方法是调用GetBuffer()方法。</p>
<p>下面以往队列加入元素为例说明如何正确地使用CString：</p>
<p>CString str = _T("new text");LVITEM item = {0};item.mask = LVIF_TEXT; item.iItem = 1; item.pszText = (LPTSTR)(LPCTSTR) str; // 错！ item.pszText = str.GetBuffer(0); // 正确ListView_SetItem ( &amp;item ); str.ReleaseBuffer(); // 将队列返回给str <br>pszText成员是LPTSTR，一个非常量指针，因此要用str的GetBuffer()。GetBuffer()的参数是CString分配的最小缓冲区。如果要分配一个1K的TCHAR，调用GetBuffer(1024)。参数为0，只返回指向字符串的指针。</p>
<p>上面示例的出错语句可以通过编译，甚至可以正常工作，如果恰好就是这个类型。但这不证明语法正确。进行非常量的强制类型转换，打破了面向对象的封装原则，并逾越了CString的内部操作。如果你习惯进行这样的强制类型转换，终会遇到出错，可你未必知道错在何处，因为你到处都在做这样的转换，而代码也都能运行。</p>
<p>&#160;</p>
<p>知道为什么人们总在抱怨有缺陷的软件吗？不正确的代码就臭虫的滋生地。然道你愿意编写明知有错的代码让臭虫有机可乘？还是花些时间学习CString的正确用法让你的代码能够100%的正确吧。</p>
<p>CString还有二个函数能够从CString中得到BSTR，并在必要时转换成Unicode。那就是AllocSysString()和SetSysString()。除了SetSysString()使用BSTR*参数外，二者一样。</p>
<p>// 转换成BSTRCString s5 = "Bob!";BSTR bs1 = NULL, bs2 = NULL;bs1 = s5.AllocSysString(); s5.SetSysString ( &amp;bs2 );// ... SysFreeString ( bs1 ); SysFreeString ( bs2 ); <br>COleVariant 与CComVariant 非常相似。COleVariant 继承于VARIANT，可以传递给需要VARIANT的函数。但又与CComVariant 不同，COleVariant 只有一个LPCTSTR的构造函数，不提供单独的LPCSTR和LPCWSTR的构造函数。在大多情况下，没有问题，因为总是愿意把字符串处理为LPCTSTR。但你必须知道这点。COleVariant 也有接受CString的构造函数。</p>
<p>// 构造CString s1 = _T("tchar string");COleVariant v1 = _T("Bob"); // 从LPCTSTR构造COleVariant v2 = s1; // 从CString拷贝 <br>对于CComVariant，必须直接处理VARIANT成员，用ChangeType()方法在必要时将其转换为字符串。但是，COleVariant::ChangeType() 在转换失败时会抛出异常，而不是返回HRESULT的出错码。</p>
<p>// 数据萃取COleVariant v3 = ...; // 从某种类型构造v3BSTR bs = NULL;try { v3.ChangeType ( VT_BSTR ); bs = v3.bstrVal; } catch ( COleException* e ) { // 出错，无法转换 }SysFreeString ( bs ); <br>WTL类 </p>
<p>&#160;</p>
<p>WTL类 <br>CString</p>
<p>WTL的CString与MFC的CString的行为完全相同，参阅上面关于MFC CString的说明即可。</p>
<p>CLR 及 VC 7 类 <br>System::String 是.NET的字符串类。在其内部，String对象是一个不变的字符序列。任何操作String对象的String方法都返回一个新的String对象，因为原有的String对象要保持不变。String类有一个特性，当多个String都指向同一组字符集时，它们其实是指向同一个对象。Managed Extensions C++ 的字符串有一个新的前缀S，用来表明是一个managed string字符串。</p>
<p>// 构造String* ms = S"This is a nice managed string"; <br>可以用unmanaged string字符串来构造String对象，但不如用managed string构造String对象有效。原因是所有相同的具有S前缀的字符串都指向同一个对象，而unmanaged string没有这个特点。下面的例子可以说明得更清楚些：</p>
<p>String* ms1 = S"this is nice";String* ms2 = S"this is nice";String* ms3 = L"this is nice";Console::WriteLine ( ms1 == ms2 ); // 输出trueConsole::WriteLine ( ms1 == ms3); // 输出false <br>要与没有S前缀的字符串做比较，用String::CompareTo()方法来实现，如：</p>
<p>Console::WriteLine ( ms1-&gt;CompareTo(ms2) ); Console::WriteLine ( ms1-&gt;CompareTo(ms3) ); <br>二者都输出0，说明字符串相等。</p>
<p>在String和MFC 7的CString之间转换很容易。CString可以转换为LPCTSTR，String有接受char* 和 wchar_t* 的二种构造函数。因此可以直接把CString传递给String的构造函数：</p>
<p>CString s1 ( "hello world" ); String* s2 ( s1 ); // 从CString拷贝 <br>反向转换的方法也类似：</p>
<p>String* s1 = S"Three cats"; CString s2 ( s1 ); <br>可能有点迷惑。从VS.NET开始，CString有一个接受String对象的构造函数，所以是正确的。</p>
<p>CStringT ( System::String* pString ); <br>为了加速操作，有时可以用基础字符串(underlying string)：</p>
<p>String* s1 = S"Three cats";Console::WriteLine ( s1 );const __wchar_t __pin* pstr = PtrToStringChars(s1);for ( int i = 0; i &lt; wcslen(pstr); i++ ) (*const_cast&lt;__wchar_t*&gt;(pstr+i))++;Console::WriteLine ( s1 ); <br>PtrToStringChars() 返回指向基础字符串的 const __wchar_t* 指针，可以防止在操作字符串时，垃圾收集器去除该字符串。</p>
<p>字符串类的打印格式函数 <br>对字符串包装类使用printf()或其它类似功能的函数时要特别小心。包括sprintf()函数及其变种，以及TRACE 和ATLTRACE 宏。它们的参数都不做类型检验，一定要给它们传递C语言字符串，而不是整个string对象。</p>
<p>例如，要向ATLTRACE()传递一个_bstr_t 里的字符串，必须显式用(LPCSTR)或 (LPCWSTR)进行强制类型转换：</p>
<p>&#160;</p>
<p>_bstr_t bs = L"Bob!"; ATLTRACE("The string is: %s in line %d\n", (LPCSTR) bs, nLine); <br>如果忘了用强制类型转换，直接把整个 _bstr_t 对象传递给ATLTRACE，跟踪消息将输出无意义的东西，因为_bstr_t 变量内的所有数据都进栈了。</p>
<p>所有类的总结 <br>常用的字符串类之间的转换方法是：将源字符串转换为C类型字符串指针，然后将该指针传递给目标类的构造函数。下面列出将字符串转换为C类型指针的方法，以及哪些类的构造函数接受C类型指针。</p>
<p>Class <br>string <br>type <br>convert to char*? <br>convert to constchar*? <br>convert to wchar_t*? <br>convert to const wchar_t*? <br>convert to BSTR? <br>construct from char*? <br>construct from wchar_t*? <br><br>_bstr_t <br>BSTR <br>yes, cast1 <br>yes, cast <br>yes, cast1 <br>yes, cast <br>yes2 <br>yes <br>yes <br><br>_variant_t <br>BSTR <br>no <br>no <br>no <br>cast to <br>_bstr_t3 <br>cast to <br>_bstr_t3 <br>yes <br>yes <br><br>string <br>MBCS <br>no <br>yes, c_str() <br>method <br>no <br>no <br>no <br>yes <br>no <br><br>wstring <br>Unicode <br>no <br>no <br>no <br>yes, c_str() <br>method <br>no <br>no <br>yes <br><br>CComBSTR <br>BSTR <br>no <br>no <br>no <br>yes, cast <br>to BSTR <br>yes, cast <br>yes <br>yes <br><br>CComVariant <br>BSTR <br>no <br>no <br>no <br>yes4 <br>yes4 <br>yes <br>yes <br><br>CString <br>TCHAR <br>no6 <br>in MBCS <br>builds, cast <br>no6 <br>in Unicode <br>builds, cast <br>no5 <br>yes <br>yes <br><br>COleVariant <br>BSTR <br>no <br>no <br>no <br>yes4 <br>yes4 <br>in MBCS builds <br>in Unicode builds <br></p>
<p>附注：</p>
<p>虽然 _bstr_t 可以转换为非常量指针，但对内部缓冲区的修改可能导致内存溢出，或在释放BSTR时导致内存泄露。 <br>bstr_t 的BSTR内含 wchar_t* 变量，所以可将const wchar_t* 转换到BSTR。但这个用法将来可能会改变，使用时要小心。 <br>如果转换到BSTR失败，将抛出异常。 <br>用ChangeType()处理VARIANT的bstrVal。在MFC，转换失败将抛出异常。 <br>虽然没有BSTR的转换函数，但AllocSysString()可返回一个新的BSTR。 <br>用GetBuffer()方法可临时得到一个非常量TCHAR指针</p>
<img src ="http://www.cppblog.com/pwqonline/aggbug/62811.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-09-26 13:11 <a href="http://www.cppblog.com/pwqonline/archive/2008/09/26/62811.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于_variant_t类</title><link>http://www.cppblog.com/pwqonline/archive/2008/09/26/62810.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Fri, 26 Sep 2008 05:09:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/09/26/62810.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/62810.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/09/26/62810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/62810.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/62810.html</trackback:ping><description><![CDATA[_variant_t类是VARIANT结构体的完全包装类，他提供了多种构造函数和数据转换函数。<br>VARIANT是一个结构体，我们可以看一下他的定义：<br>struct&nbsp; tagVARIANT<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; union <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct&nbsp; __tagVARIANT<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARTYPE vt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wReserved3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG lVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BYTE bVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SHORT iVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FLOAT fltVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOUBLE dblVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARIANT_BOOL boolVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _VARIANT_BOOL bool;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SCODE scode;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CY cyVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE date;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BSTR bstrVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown __RPC_FAR *punkVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDispatch __RPC_FAR *pdispVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAFEARRAY __RPC_FAR *parray;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BYTE __RPC_FAR *pbVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SHORT __RPC_FAR *piVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG __RPC_FAR *plVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FLOAT __RPC_FAR *pfltVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOUBLE __RPC_FAR *pdblVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARIANT_BOOL __RPC_FAR *pboolVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _VARIANT_BOOL __RPC_FAR *pbool;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SCODE __RPC_FAR *pscode;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CY __RPC_FAR *pcyVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE __RPC_FAR *pdate;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BSTR __RPC_FAR *pbstrVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown __RPC_FAR *__RPC_FAR *ppunkVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDispatch __RPC_FAR *__RPC_FAR *ppdispVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAFEARRAY __RPC_FAR *__RPC_FAR *pparray;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARIANT __RPC_FAR *pvarVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PVOID byref;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR cVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USHORT uiVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG ulVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INT intVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT uintVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECIMAL __RPC_FAR *pdecVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR __RPC_FAR *pcVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USHORT __RPC_FAR *puiVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG __RPC_FAR *pulVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INT __RPC_FAR *pintVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT __RPC_FAR *puintVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct&nbsp; __tagBRECORD<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PVOID pvRecord;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IRecordInfo __RPC_FAR *pRecInfo;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;__VARIANT_NAME_4;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;__VARIANT_NAME_3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;__VARIANT_NAME_2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECIMAL decVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;__VARIANT_NAME_1;<br>&nbsp;&nbsp;&nbsp; };<br>
<img src ="http://www.cppblog.com/pwqonline/aggbug/62810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-09-26 13:09 <a href="http://www.cppblog.com/pwqonline/archive/2008/09/26/62810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++中的类</title><link>http://www.cppblog.com/pwqonline/archive/2008/09/24/62672.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Wed, 24 Sep 2008 06:06:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/09/24/62672.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/62672.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/09/24/62672.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/62672.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/62672.html</trackback:ping><description><![CDATA[有一句话说的很是经典，类就是定义了一个新的类型和一个新的作用域。<br>
<img src ="http://www.cppblog.com/pwqonline/aggbug/62672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-09-24 14:06 <a href="http://www.cppblog.com/pwqonline/archive/2008/09/24/62672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>获取程序当前执行文件名-GetModuleFileName的用法</title><link>http://www.cppblog.com/pwqonline/archive/2008/09/10/61489.html</link><dc:creator>你弹我唱</dc:creator><author>你弹我唱</author><pubDate>Wed, 10 Sep 2008 07:04:00 GMT</pubDate><guid>http://www.cppblog.com/pwqonline/archive/2008/09/10/61489.html</guid><wfw:comment>http://www.cppblog.com/pwqonline/comments/61489.html</wfw:comment><comments>http://www.cppblog.com/pwqonline/archive/2008/09/10/61489.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwqonline/comments/commentRss/61489.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwqonline/services/trackbacks/61489.html</trackback:ping><description><![CDATA[<h2>&nbsp;</h2>
<div class=postbody>用GetModuleFileName获取程序当前执行文件名 <br><br>需要获得程序当前的运行目录，这时就可以使用GetModuleFileName函数<br>DWORD WINAPI GetModuleFileName(<br>&nbsp; HMODULE <em>hModule</em>,<br>&nbsp; LPTSTR <em>lpFileName</em>,<br>&nbsp; DWORD <em>nSize</em><br>);<br><br>hModule：要获取文件名的模块名柄,null表示当前模块<br>lpFileName:输出参数，存放取得的文件名<br>nSize:lpFileName参数的长度<br><br>例<br>void FileName()<br>{<br>&nbsp;&nbsp;&nbsp; TCHAR lpFileName[MAX_PATH];<br>&nbsp;&nbsp;&nbsp; ::GetModuleFileName(null, lpFileName, MAX_PATH);<br>&nbsp;&nbsp;&nbsp; SetDlgItemText(IDC_TEXTBOX, lpFileName);<br>}</div>
<img src ="http://www.cppblog.com/pwqonline/aggbug/61489.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwqonline/" target="_blank">你弹我唱</a> 2008-09-10 15:04 <a href="http://www.cppblog.com/pwqonline/archive/2008/09/10/61489.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>