﻿<?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++博客-唐吉诃德-文章分类-VC/MFC</title><link>http://www.cppblog.com/tdweng/category/13586.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 30 Jun 2012 17:17:38 GMT</lastBuildDate><pubDate>Sat, 30 Jun 2012 17:17:38 GMT</pubDate><ttl>60</ttl><item><title>VC 6.0 常见断言错误总结</title><link>http://www.cppblog.com/tdweng/articles/144887.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Sat, 23 Apr 2011 18:33:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/144887.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/144887.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/144887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/144887.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/144887.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/xusuai5820016/archive/2010/06/28/5699824.aspx">http://blog.csdn.net/xusuai5820016/archive/2010/06/28/5699824.aspx</a>
<img src ="http://www.cppblog.com/tdweng/aggbug/144887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-04-24 02:33 <a href="http://www.cppblog.com/tdweng/articles/144887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC错误解析方案集合</title><link>http://www.cppblog.com/tdweng/articles/139244.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 24 Jan 2011 13:58:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/139244.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/139244.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/139244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/139244.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/139244.html</trackback:ping><description><![CDATA[<span style="COLOR: #ff0000"><strong>1.error LNK2019:unresolved external symbol *** referenced in functio...</strong></span> <br><br>
<p style="COLOR: #ff0000">当头文件中声明了一个函数，但是在相应的源文件中却没有对该函数进行定义，则会出现为&#8220;解决的外部符号&#8221;（unresolved external symbol ）错误。另外，当一个函数调用了外部的一个库文件中的函数，但是在当前project的properties中并没有将所依赖的（dependent）库文件包含进来时，也会出现这种错误。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #ff0000">综上，当一个solution在linking时找不到所涉及到的函数的定义时就会出现&#8220;unresolved external symbol &#8221;错误</span>。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;例如，下面是调用rapi的库文件rapi.lib中的函数时，由于没有将rapi.lib包含进来而导致的链接错误。</p>
<p>1&gt;Linking...<br>WMFileSync.obj : error LNK2019: unresolved external symbol <a>_CeFindClose@4</a> referenced in function "public: virtual long __stdcall CWMFileSync::IsFileExists(wchar_t *)" (<a>?IsFileExists@CWMFileSync@@UAGJPA_W@Z</a>)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #ff0000">【解决方案】</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #ff0000; BACKGROUND-COLOR: yellow">1. Project -&gt; ** Properties... -&gt; Configuration Properties -&gt; Linker -&gt; Input -&gt; Additional Dependencies -&gt; rapi.lib</span></p>
<p>另外，在此之前，还需添加rapi库的相应目录：Tools -&gt; Options -&gt; Projects and Solutions -&gt; VC++ Directories -&gt; Show Directories for -&gt; 在Include files中添加C:\Program Files\Matrox Imaging\rapi\Include 以及 Tools -&gt; Options -&gt; Projects and Solutions -&gt; VC++ Directories -&gt; Show Directories for -&gt; 在Library files中添加C:\Program Files\Matrox Imaging\rapi\LIB。添加目录的目的是为了使VC在调用相应库文件时不必总是使用绝对地址，VC可以通过文件名在所包含的目录中进行搜索。这样，前面的rapi.lib就不必使用绝对地址了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 【缺点】可移植性差，如果将原工程中的源文件和头文件中的内容copy下来重新建立该工程时（例如：在电子书或网络上找到的程序），仍需自己在工程中添加目录及所需的库文件。</p>
<p>&nbsp;&nbsp;<span style="COLOR: #ff0000; BACKGROUND-COLOR: yellow">&nbsp;&nbsp;&nbsp;&nbsp; 2. 在程序前加入#pragma commet(lib, "rapi.lib")也可以达到相同的效果。</span></p>
<img src ="http://www.cppblog.com/tdweng/aggbug/139244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-01-24 21:58 <a href="http://www.cppblog.com/tdweng/articles/139244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>window消息</title><link>http://www.cppblog.com/tdweng/articles/139241.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 24 Jan 2011 13:14:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/139241.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/139241.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/139241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/139241.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/139241.html</trackback:ping><description><![CDATA[<p>PreTranslateMessage的理解:<br>&nbsp;&nbsp;&nbsp; PreTranslateMessage只能处理消息队列中的消息,也就是由PostMessage发出的消息/鼠标键盘消息等.<br>&nbsp;&nbsp;&nbsp; SendMessage发送的消息并不放在消息队列中,而是直接调用处理函数进行处理,所以这种消息用PreTranslateMessage的捕获不到的,如WM_KIllFOCUS和WM_SETFOCUS.<br>&nbsp;&nbsp;&nbsp; SendMessage的消息是直接执行处理函数的,它要等消息执行完才返回(执行完SendMessage函数);而PostMessage则把消息发送后立即返回,把消息挂到消息队列中等待执行,所以以下的程序是错的!!<br>#include &lt;windows.h&gt;<br>int main()<br>{<br>&nbsp; PostMessage(HWND_BROADCAST,WM_QUIT,0,0);<br>&nbsp; return 0;<br>}</p>
<p>PostMessage将消息WM_QUIT发送到消息队列中,由于PostMessage的立即返回(即结束)就执行下一句语句结束整个程序,消息还挂在消息队列中未处理故出错!!</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/139241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-01-24 21:14 <a href="http://www.cppblog.com/tdweng/articles/139241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetLastError返回值的意义</title><link>http://www.cppblog.com/tdweng/articles/138242.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 10 Jan 2011 04:00:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/138242.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/138242.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/138242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/138242.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/138242.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp;GetLastError返回值的意义〖0〗-操作成功完成。〖1〗-功能错误。〖2〗-系统找不到指定的文件。〖3〗-系统找不到指定的路径。〖4〗-系统无法打开文件。〖5〗-拒绝访问。〖6〗-句柄无效。〖7〗-存储控制块被损坏。〖8〗-存储空间不足，无法处理此命令。〖9〗-存储控制块地址无效。〖10〗-环境错误。〖11〗-试图加载格式错误的程序。〖12〗-访问码无效。〖1...&nbsp;&nbsp;<a href='http://www.cppblog.com/tdweng/articles/138242.html'>阅读全文</a><img src ="http://www.cppblog.com/tdweng/aggbug/138242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-01-10 12:00 <a href="http://www.cppblog.com/tdweng/articles/138242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CWnd、HWND、GetSafeHwnd() </title><link>http://www.cppblog.com/tdweng/articles/137781.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Fri, 31 Dec 2010 01:44:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/137781.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/137781.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/137781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/137781.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/137781.html</trackback:ping><description><![CDATA[<font color=#0000ff>当我们想得到一个窗口对象（CWnd的派生对象）指针的句柄（HWND）时，最安全的方法是使用GetSafeHwnd()函数，通过下面的例子来看其理由：<br><span style="COLOR: red">CWnd *pwnd = FindWindow(&#8220;ExploreWClass&#8221;,NULL); //希望找到资源管理器<br>HWND hwnd = pwnd-&gt;m_hwnd; //得到它的HWND</span><br>这样的代码当开始得到的pwnd为空的时候就会出现一个&#8220;General protection error&#8221;,并关闭应用程序，因为一般不能对一个NULL指针访问其成员，如果用下面的代码：<br><span style="COLOR: red">CWnd *pwnd = FindWindow(&#8220;ExploreWClass&#8221;,NULL); //希望找到资源管理器<br>HWND hwnd = pwnd-&gt;GetSafeHwnd(); //得到它的HWND</span><br>就不会出现问题，因为尽管当pwnd是NULL时，GetSafeHwnd仍然可以用，只是返回NULL，通过GetSafeHwnd()的实现代码就更清楚了：<br><span style="COLOR: red">_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const<br>{<br>return this == NULL?NULL:m_hWnd;<br>}</span><br>你看有很多函数的参数要求HWND,它就可以派上用场了.<br>HWND hwnd;<br>CWnd* pWnd;<br>pWnd=((CFrameWnd*)(AfxGetApp()-&gt;m_pMainWnd))-&gt;GetActiveView();<br>hwnd=pWnd-&gt;GetDlgItem(IDC_EDIT2)-&gt;GetSafeHwnd();<br>::SetWindowText(hwnd,m_strResult); <br>转载:</font><a title=http://hi.baidu.com/johnleeqq/blog/item/ae746a5088f4535f1138c2b2.html href="http://hi.baidu.com/johnleeqq/blog/item/ae746a5088f4535f1138c2b2.html"><font color=#525252>http://hi.baidu.com/johnleeqq/blog/item/ae746a5088f4535f1138c2b2.html</font></a> 
<img src ="http://www.cppblog.com/tdweng/aggbug/137781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-12-31 09:44 <a href="http://www.cppblog.com/tdweng/articles/137781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CString详细讲解 </title><link>http://www.cppblog.com/tdweng/articles/136133.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Sat, 11 Dec 2010 03:53:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/136133.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/136133.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/136133.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/136133.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/136133.html</trackback:ping><description><![CDATA[<div class="postText"><span style="color: #ff0000; background-color: #ffff00; ">释放</span>前言：串操作是编程中最常用也最基本的操作之一。 做为VC程序员，无论是菜鸟或高手都曾用过Cstring。而且好像实际编程中很难离得开它（虽然它不是标准Ｃ++中的库）。因为MFC中提供的这个类对我们操作字串实在太方便了，CString不仅提供各种丰富的操作函数、操作符重载，使我们使用起串起来更象basic中那样直观；而且它还提供了动态内存分配，使我们减少了多少字符串数组越界的隐患。但是，我们在使用过程中也体会到CString简直太容易出错了，而且有的不可捉摸。所以有许多高人站过来，建议抛弃它。
<p>&nbsp;</p>
<p>在此，我个人认为：CString封装得确实很完美，它有许多优点，如&#8220;容易使用 ，功能强，动态分配内存，大量进行拷贝时它很能节省内存资源并且执行效率高，与标准Ｃ完全兼容，同时支持多字节与宽字节，由于有异常机制所以使用它安全方便&#8221; 其实，使用过程中之所以容易出错，那是因为我们对它了解得还不够，特别是它的实现机制。因为我们中的大多数人，在工作中并不那么爱深入地去看关于它的文档，何况它还是英文的。 </p>
<p>由于前几天我在工作中遇到了一个本不是问题但却特别棘手、特别难解决而且莫名惊诧的问题。好来最后发现是由于CString引发的。所以没办法，我把整个CString的实现全部看了一遍，才慌然大悟，并彻底弄清了问题的原因(这个问题，我已在csdn上开贴)。在此，我想把我的一些关于CString的知识总结一番，以供他（她）人借鉴，也许其中有我理解上的错误，望发现者能通知我，不胜感谢。</p>
<p>&nbsp;</p>
<p>1． CString实现的机制.</p>
<p>CString是通过&#8220;引用&#8221;来管理串的，&#8220;引用&#8221;这个词我相信大家并不陌生，象Window内核对象、COM对象等都是通过引用来实现的。而CString也是通过这样的机制来管理分配的内存块。实际上CString对象只有一个指针成员变量,所以任何CString实例的长度只有4字节.</p>
<p>即: int len = sizeof(CString);//len等于4</p>
<p>这个指针指向一个相关的引用内存块，如图: CString str("abcd");</p>
<p>&#8216;A&#8217;</p>
<p>&#8216;B&#8217;</p>
<p>&#8216;C&#8217;</p>
<p>&#8216;D&#8217;</p>
<p>&nbsp;&nbsp; 0</p>
<p>0x04040404 head部，为引用内存块相关信息</p>
<p>&nbsp;</p>
<p>str 0x40404040</p>
<p>正因为如此，一个这样的内存块可被多个CString所引用，例如下列代码：</p>
<p>CString str("abcd");</p>
<p>CString a = str;</p>
<p>CString b(str);</p>
<p>CString c;</p>
<p>c = b;</p>
<p>上面代码的结果是：上面四个对象(str,a,b,c)中的成员变量指针有相同的值，都为0x40404040.而这块内存块怎么知道有多少个CString引用它呢？同样，它也会记录一些信息。如被引用数，串长度，分配内存长度。</p>
<p>这块引用内存块的结构定义如下：</p>
<p style="color: red">struct CStringData</p>
<p style="color: red">{</p>
<p style="color: red">long nRefs; //表示有多少个CString 引用它. 4</p>
<p style="color: red">int nDataLength; //串实际长度. 4</p>
<p style="color: red">int nAllocLength; //总共分配的内存长度（不计这头部的12字节）. 4</p>
<p>};</p>
<p>由于有了这些信息，CString就能正确地分配、管理、释放引用内存块。</p>
<p>如果你想在调试程序的时候获得这些信息。可以在Watch窗口键入下列表达式：</p>
<p>(CStringData*)((CStringData*)(this-&gt;m_pchData)-1)或</p>
<p>(CStringData*)((CStringData*)(str.m_pchData)-1)//str为指CString实例</p>
<p>&nbsp;</p>
<p>正因为采用了这样的好机制，使得CString在大量拷贝时，不仅效率高，而且分配内存少。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong><span style="color: red">2．LPCTSTR 与 GetBuffer(int nMinBufLength)</span> </strong></p>
<p>这两个函数提供了与标准C的兼容转换。在实际中使用频率很高，但却是最容易出错的地方。这两个函数实际上返回的都是指针，但它们有何区别呢？以及调用它们后，幕后是做了怎样的处理过程呢？</p>
<p><span style="color: red">(1) LPCTSTR 它的执行过程其实很简单，只是返回引用内存块的串地址。 它是作为操作符重载提供的，所以在代码中有时可以隐式转换，而有时却需强制转制。如：</span></p>
<p><u style="color: #ff0000">CString str;</u></p>
<p><u style="color: #ff0000">const char* p = (LPCTSTR)str;</u></p>
<p>//假设有这样的一个函数，Test(const char* p)； 你就可以这样调用</p>
<p>Test(str);//这里会隐式转换为LPCTSTR</p>
<p><span style="color: #ff0000">(2) GetBuffer(int nMinBufLength) 它类似，也会返回一个指针，不过它有点差别,返回的是LPTSTR</span></p>
<p><span style="color: #ff0000">(3) 这两者到底有何不同呢？我想告诉大家，其本质上完全不一样，一般说LPCTSTR转换后只应该当常量使用，或者做函数的入参；而GetBuffer(...)取出指针后，可以通过这个指针来修改里面的内容，或者做函数的出参。为什么呢？也许经常有这样的代码：</span></p>
<p>CString str("abcd");</p>
<p>char* p = (char*)(const char*)str;</p>
<p>p[2] = 'z'; </p>
<p>其实，也许有这样的代码后，你的程序并没有错，而且程序也运行得挺好。但它却是非常危险的。再看</p>
<p>CString str("abcd");</p>
<p>CString test = str;</p>
<p>....</p>
<p>char* p = (char*)(const char*)str;</p>
<p>p[2] = 'z'; </p>
<p>strcpy(p, "akfjaksjfakfakfakj");//这下完蛋了 </p>
<p>你知道此时，test中的值是多少吗？答案是"abzd"。它也跟着改变了，这不是你所期望发生的。但为什么会这样呢？你稍微想想就会明白，前面说过，因为CString是指向引用块的，str与test指向同一块地方,当你p[2]='z'后，当然test也会随着改变。所以用它做LPCTSTR做转换后，你只能去读这块数据，千万别去改变它的内容。</p>
<p>&nbsp;</p>
<p>假如我想直接通过指针去修改数据的话，那怎样办呢？就是用GetBuffer(...).看下述代码：</p>
<p>CString str("abcd");</p>
<p>CString test = str;</p>
<p>....</p>
<p>char* p = str.GetBuffer(20);</p>
<p>p[2] = 'z'; // 执行到此，现在test中值却仍是"abcd"</p>
<p>strcpy(p, "akfjaksjfakfakfakj"); // 执行到此，现在test中值还是"abcd"</p>
<p>为什么会这样？其实GetBuffer(20)调用时，它实际上另外建立了一块新内块存，并分配20字节长度的buffer，而原来的内存块引用计数也相应减1. 所以执行代码后str与test是指向了两块不同的地方，所以相安无事。</p>
<p><span style="color: #ff0000">(4) 不过这里还有一点注意事项：就是str.GetBuffer(20)后，str的分配长度为20，即指针p它所指向的buffer只有20字节长，给它赋值时，切不可超过，否则灾难离你不远了；如果指定长度小于原来串长度，如GetBuffer(1),实际上它会分配4个字节长度（即原来串长度）；另外，当调用GetBuffer(...)后并改变其内容，一定要记得调用ReleaseBuffer(),这个函数会根据串内容来更新引用内存块的头部信息。</span></p>
<p>(5) 最后还有一注意事项，看下述代码：</p>
<p>char* p = NULL;</p>
<p>const char* q = NULL;</p>
<p>{</p>
<p>CString str = "abcd";</p>
<p>q = (LPCTSTR)str;</p>
<p>p = str.GetBuffer(20);</p>
<p>AfxMessageBox(q);// 合法的</p>
<p>strcpy(p, "this is test");//合法的，</p>
<p>}</p>
<p>AfxMessageBox(q);// 非法的，可能完蛋</p>
<p>strcpy(p, "this is test");//非法的，可能完蛋</p>
<p>这里要说的就是，当返回这些指针后， 如果CString对象生命结束，这些指针也相应无效。</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000; background-color: yellow; "><strong>3．拷贝 &amp; 赋值 &amp; "引用内存块" 什么时候释放？</strong></span></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; ">下面演示一段代码执行过程</span></p>
<p><span style="color: #0000ff; ">void Test()</span></p>
<p><span style="color: #0000ff; ">{</span></p>
<p><span style="color: #0000ff; ">CString str("abcd");</span></p>
<p><span style="color: #0000ff; ">//str指向一引用内存块（引用内存块的引用计数为1,长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">CString a;</span></p>
<p><span style="color: #0000ff; ">//a指向一初始数据状态，</span></p>
<p><span style="color: #0000ff; ">a = str;</span></p>
<p><span style="color: #0000ff; ">//a与str指向同一引用内存块（引用内存块的引用计数为2,长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">CString b(a);</span></p>
<p><span style="color: #0000ff; ">//a、b与str指向同一引用内存块（引用内存块的引用计数为3,长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">{</span></p>
<p><span style="color: #0000ff; ">LPCTSTR temp = (LPCTSTR)a;</span></p>
<p><span style="color: #0000ff; ">//temp指向引用内存块的串首地址。（引用内存块的引用计数为3,长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">CString d = a;</span></p>
<p><span style="color: #0000ff; ">//a、b、d与str指向同一引用内存块（引用内存块的引用计数为4, 长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">b = "testa";</span></p>
<p><span style="color: #0000ff; ">//这条语句实际是调用CString::operator=(CString&amp;)函数。 b指向一新分配的引用内存块。（新分配的引用内存块的 引用计数为1, 长度为5, 分配长度为5）</span></p>
<p><span style="color: #0000ff; ">//同时原引用内存块引用计数减1. a、d与str仍指向原 引用内存块（引用内存块的引用计数为3,长度为4,分配长度为4） </span></p>
<p><span style="color: #0000ff; ">}</span></p>
<p><span style="color: #0000ff; ">//由于d生命结束，调用析构函数，导至引用计数减1（引用内存块的引用计数为2,长度为4,分配长度为4）</span></p>
<p><span style="color: #0000ff; ">LPTSTR temp = a.GetBuffer(10);</span></p>
<p><span style="color: #0000ff; ">//此语句也会导致重新分配新内存块。temp指向新分配引用内存块的串首地址（新 分配的引用内存块的引用计数为1,长度为0,分配长度为10）</span></p>
<p><span style="color: #0000ff; ">//同时原引用内存块引用计数减1. 只有str仍 指向原引用内存块 （引用内存块的引用计数为1, 长度为4, 分配长度为4） </span></p>
<p><span style="color: #0000ff; ">strcpy(temp, "temp"); </span></p>
<p><span style="color: #0000ff; ">//a指向的引用内存块的引用计数为1,长度为0,分配长度为10 a.ReleaseBuffer();//注意:a指向的引用内存块的引用计数为1,长度为4,分配长度为10</span></p>
<p><span style="color: #0000ff; ">}</span></p>
<p><span style="color: #0000ff; ">//执行到此，所有的局部变量生命周期都已结束。对象str a b 各自调用自己的析构构</span></p>
<p><span style="color: #0000ff; ">//函数，所指向的引用内存块也相应减1</span></p>
<p><span style="background-color: yellow; color: #0000ff; ">//注意，str a b 所分别指向的引用内存块的计数均为0,这导致所分配的内存块释放</span></p>
<p><span style="color: #0000ff; background-color: yellow; ">//CString分配的内存在堆里，只有这块&nbsp;</span><span style="background-color: yellow; color: #0000ff; ">引用内存块的计数均为0，才</span><span style="background-color: yellow; color: #0000ff; ">释放内存</span></p>
<p>通过观察上面执行过程，我们会发现CString虽然可以多个对象指向同一引用内块存，但是它们在进行各种拷贝、赋值及改变串内容时，它的处理是很智能并且非常安全的，完全做到了互不干涉、互不影响。当然必须要求你的代码使用正确恰当，特别是实际使用中会有更复杂的情况，如做函数参数、引用、及有时需保存到CStringList当中，如果哪怕有一小块地方使用不当，其结果也会导致发生不可预知的错误</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><strong>5 FreeExtra()的作用</strong></span></p>
<p>看这段代码</p>
<p>(1) CString str("test");</p>
<p>(2) LPTSTR temp = str.GetBuffer(50);</p>
<p>(3) strcpy(temp, "there are 22 character");</p>
<p>(4) str.ReleaseBuffer();</p>
<p>(5) str.FreeExtra();</p>
<p>上面代码执行到第(4)行时，大家都知道str指向的引用内存块计数为1,长度为22,分配长度为50. 那么执行str.FreeExtra()时，它会释放所分配的多余的内存。(引用内存块计数为1,长度为22,分配长度为22)</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><strong>6 Format(...) 与 FormatV(...)</strong></span></p>
<p>这条语句在使用中是最容易出错的。因为它最富有技巧性，也相当灵活。在这里，我没打算对它细细分析，实际上sprintf(...)怎么用，它就怎么用。我只提醒使用时需注意一点：就是它的参数的特殊性，由于编译器在编译时并不能去校验格式串参数与对应的变元的类型及长度。所以你必须要注意，两者一定要对应上，</p>
<p>否则就会出错。如：</p>
<p>CString str;</p>
<p>int a = 12;</p>
<p>str.Format("first:%l, second: %s", a, "error");//result?试试</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><strong>7 LockBuffer() 与 UnlockBuffer()</strong></span></p>
<p>顾名思议，这两个函数的作用就是对引用内存块进行加锁及解锁。但使用它有什么作用及执行过它后对CString串有什么实质上的影响。其实挺简单，看下面代码:</p>
<p>(1) CString str("test");</p>
<p>(2) str.LockBuffer();</p>
<p>(3) CString temp = str;</p>
<p>(4) str.UnlockBuffer();</p>
<p>(5) str.LockBuffer();</p>
<p>(6) str = "error";</p>
<p>(7) str.ReleaseBuffer();</p>
<p>执行完(3)后，与通常情况下不同，temp与str并不指向同一引用内存块。你可以在watch窗口用这个表达式(CStringData*)((CStringData*)(str.m_pchData)-1)看看。</p>
<p>其实在msdn中有说明：</p>
<p>While in a locked state, the string is protected in two ways: </p>
<p>&nbsp;</p>
<p>No other string can get a reference to the data in the locked string, even if that string is assigned to the locked string.</p>
<p>The locked string will never reference another string, even if that other string is copied to the locked string. </p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><strong>8 CString 只是处理串吗？</strong></span></p>
<p>不对，CString不只是能操作串，而且还能处理内存块数据。功能完善吧！看这段代码</p>
<p>char p[20];</p>
<p>for(int loop=0; loop&lt;sizeof(p); loop++)</p>
<p>{</p>
<p>p[loop] = 10-loop;</p>
<p>}</p>
<p>CString str((LPCTSTR)p, 20);</p>
<p>char temp[20];</p>
<p>memcpy(temp, str, str.GetLength());</p>
<p>str完全能够转载内存块p到内存块temp中。所以能用CString来处理二进制数据</p>
<p>&nbsp;</p>
<p>8 AllocSysString()与SetSysString(BSTR*) </p>
<p>这两个函数提供了串与BSTR的转换。使用时须注意一点：当调用AllocSysString()后，须调用它SysFreeString(...) </p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><strong>9 参数的安全检验</strong></span></p>
<p>在MFC中提供了多个宏来进行参数的安全检查，如：ASSERT. 其中在CString中也不例外，有许多这样的参数检验，其实这也说明了代码的安全性高，可有时我们会发现这很烦，也导致Debug与Release版本不一样，如有时程序Debug通正常，而Release则程序崩溃；而有时恰相反，Debug不行，Release行。其实我个人认为，我们对CString的使用过程中，应力求代码质量高，不能在Debug版本中出现任何断言框，哪怕release运行似乎看起来一切正常。但很不安全。如下代码：</p>
<p>(1) CString str("test");</p>
<p>(2) str.LockBuffer();</p>
<p>(3) LPTSTR temp = str.GetBuffer(10);</p>
<p>(4) strcpy(temp, "error");</p>
<p>(5) str.ReleaseBuffer();</p>
<p>(6) str.ReleaseBuffer();//执行到此时，Debug版本会弹出错框</p>
<p>&nbsp;</p>
<p>10 CString的异常处理</p>
<p>我只想强调一点：只有分配内存时，才有可能导致抛出CMemoryException.</p>
<p>同样，在msdn中的函数声明中，注有throw( CMemoryException)的函数都有重新分配或调整内存的可能。</p>
<p>&nbsp;</p>
<p>11 跨模块时的Cstring。即一个DLL的接口函数中的参数为CString&amp;时，它会发生怎样的现象。解答我遇到的问题。我的问题原来已经发贴，地址为：</p>
<p>http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136</p>
<p>&nbsp;</p>
<p>构造一个这样CString对象时，如CString str，你可知道此时的str所指向的引用内存块吗？也许你会认为它指向NULL。其实不对，如果这样的话，CString所采用的引用机制管理内存块就会有麻烦了，所以CString在构造一个空串的对象时，它会指向一个固定的初始化地址，这块数据的声明如下：</p>
<p>AFX_STATIC_DATA int _afxInitData[] = {-1,0,0,0};</p>
<p>简要描述概括一下：当某个CString对象串置空的话，如Empty(),CString a等，它的成员变量m_pchData就会指向_afxInitData这个变量的地址。当这个CString对象生命周期结束时，正常情况下它会去对所指向的引用内存块计数减1，如果引用计数为0(即没有任何CString引用它时)，则释放这块引用内存。而现在的情况是如果CString所指向的引用内存块是初始化内存块时，则不会释放任何内存。</p>
<p>&nbsp;</p>
<p>说了这么多，这与我遇到的问题有什么关系呢？其实关系大着呢？其真正原因就是如果exe模块与dll模块有一个是static编译连接的话。那么这个CString初始化数据在exe模块与dll模块中有不同的地址，因为static连接则会在本模块中有一份源代码的拷贝。另外一种情况，如果两个模块都是share连接的，CString的实现代码则在另一个单独的dll中实现，而AFX_STATIC_DATA指定变量只装一次，所以两个模块中_afxInitData有相同的地址。</p>
<p>现在问题完全明白了吧！你可以自己去演示一下。</p>
<p>__declspec (dllexport) void test(CString&amp; str)</p>
<p>{</p>
<p>str = "abdefakdfj";//如果是static连接，并且传入的str为空串的话，这里出错。</p>
<p>}</p>
<p>&nbsp;</p>
<p>最后一点想法：写得这里，其实CString中还有许多技巧性的好东东，我并没去解释。如很多重载的操作符、查找等。我认为还是详细看看msdn，这样也许会比我讲的好多了。我只侧重那些可能会出错的情况。当然，如我上面叙述中有错误，敬请高手指点，不胜感谢！<br /><br /><br />msdn：<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp</a></p>
</div><img src ="http://www.cppblog.com/tdweng/aggbug/136133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-12-11 11:53 <a href="http://www.cppblog.com/tdweng/articles/136133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual Assist X 完美破解</title><link>http://www.cppblog.com/tdweng/articles/124388.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 23 Aug 2010 02:49:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/124388.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/124388.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/124388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/124388.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/124388.html</trackback:ping><description><![CDATA[首先声明:请支持正版.<br><br>作者:<a href="http://www.cppblog.com/pengkuny/"><u><font color=#0000ff>pengkuny</font></u></a><br><br>我费了九牛二虎之力,才找到这个破解版.一般的试用版只能使用30天,这个时候,你再重装Visual Assist X是没有用的,Visual Assist X防破解的工作做得比较好,除非你重装系统.而且Visual Assist X的版本更新快,版本号纷繁复杂,一味追求新版本的的人经常因为找不到注册码,导致原版本也不能使用.<br><br>所以,以后只用这个:<br><br><strong style="COLOR: #800080">[请跳过直接看后记]</strong><br><br>第一步:<br>下载Visual Assist X .V10.3.1549<br>官方原版下载:<br><a href="http://www.wholetomato.com/downloads/VA_X_Setup1549.exe"><u><font color=#0000ff>http://www.wholetomato.com/downloads/VA_X_Setup1549.exe</font></u></a><br>破解文件:<br><a href="http://revenge.crackdb.com/rlz/visual.assist.x.10.3.1549.0.cracked.dll-rev.zip"><u><font color=#0000ff>http://revenge.crackdb.com/rlz/visual.assist.x.10.3.1549.0.cracked.dll-rev.zip</font></u></a><br><br>第二步:<br>将原来安装的版本删除，<br>然后在注册表中将带有&#8220;<strong style="COLOR: red">tomato</strong>&#8221;关键字并且确保不是其他软件的键和值都删除，<br><br>第三步:<br>安装1549的原版，<span style="COLOR: red"><strong>装完后不要马上运行VC</strong>，</span><br><br>第四步:<br>将破解文件<span style="COLOR: red"><strong>替换</strong></span>好，<br>然后再将注册表文件<span style="COLOR: red"><strong>导入</strong></span>。<br><br>第五步:<br>OK! <br><br><span style="COLOR: #800080"><strong>[后记]:<br></strong></span>根据softgenie的回复, 这个破解版做得并不好,有某些功能失效, 并且常常导致程序无响应.<br>如果你使用的是VC6的话,可以用这个网页的Visual Assist 6.0,破解的比较好(<span style="COLOR: #800080"><strong>但在VS 2005中用不了</strong></span>):<br><a href="http://www.vckbase.com/tools/listtools.asp?tclsid=109" target=_blank><u><font color=#0000ff>http://www.vckbase.com/tools/listtools.asp?tclsid=109</font></u></a>.<br>装之前仍然要先经过前面所述的<span style="COLOR: red"><strong>第二步</strong></span>,清理注册表.<br>
<img src ="http://www.cppblog.com/tdweng/aggbug/124388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-08-23 10:49 <a href="http://www.cppblog.com/tdweng/articles/124388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AFX_MANAGE_STATE(AfxGetStaticModuleState());</title><link>http://www.cppblog.com/tdweng/articles/120339.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Wed, 14 Jul 2010 07:39:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/120339.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/120339.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/120339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/120339.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/120339.html</trackback:ping><description><![CDATA[<p>AFX_MANAGE_STATE(AfxGetStaticModuleState());//用于模块切换时的状态保护，
<p>1.AfxGetStaticModuleState()指向当前模块状态;
<p>2.当前函数调用结束后原模块的状态自动被恢复；
<p>3.用于DLL中所调用MFC函数、类、资源时的模块状态切换;</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/120339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-07-14 15:39 <a href="http://www.cppblog.com/tdweng/articles/120339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从访问0xcccccccc异常说起</title><link>http://www.cppblog.com/tdweng/articles/119404.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Tue, 06 Jul 2010 01:07:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/119404.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/119404.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/119404.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/119404.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/119404.html</trackback:ping><description><![CDATA[<p>在VC6下调试程序，可能会遇到诸如指令引用&#8220;<span style="COLOR: red">0xcccccccc</span>&#8221;,该内存不能为Read的报错</p>
<p>究其原因，就debug版中的堆栈中的局部变量（包括指针）在明确初始化之前都用0x0cc进行初始化，因此，未初始化时候的指针是指向地址0x0cccccccc的，而这段地址一来是处于内核地址空间，一般的应用程序是无权访问的，上面的报错就是这样产生的。因此，一旦遇到上述报错，基本可以认定程序中出现了野指针。</p>
<p>另外一方面cc对应着int 3调试中断，堆栈中的存放的局部数据一般情况下是只读的，当发生意外执行堆栈里面的数据就会引发该调试中断。</p>
<p>可以认为0x0cc就是有特殊含义的占位符，对于指针而言，它跟NULL是一个意思，其它具有特殊意义的占位符还有：</p>
<p><span style="COLOR: red">0xcdcdcdcd - Created but not initialized</span></p>
<p>0xdddddddd - Deleted</p>
<p><span style="COLOR: red">0xfeeefeee - Freed memory set by NT's heap manager</span></p>
<p>0xcccccccc - Uninitialized locals in VC6 when you compile w/ /GZ</p>
<p style="COLOR: red">0xabababab - Memory following a block allocated by LocalAlloc()</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/119404.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-07-06 09:07 <a href="http://www.cppblog.com/tdweng/articles/119404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UNREFERENCED_PARAMETER的用处</title><link>http://www.cppblog.com/tdweng/articles/113526.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Sun, 25 Apr 2010 11:24:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/113526.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/113526.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/113526.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/113526.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/113526.html</trackback:ping><description><![CDATA[<p>作用：告诉编译器，已经使用了该变量，不必检测警告！</p>
<p>在VC编译器下，如果您用最高级别进行编译，编译器就会很苛刻地指出您的非常细小的警告。当你生命了一个变量，而没有使用时，编译器就会报警告：</p>
<p>&#8220;warning C4100: ''ＸＸＸＸ'' : unreferenced formal parameter.&#8221; </p>
<p>所以，为了让编译器不必检测你的警告，就使用UNREFERENCED_PARAMETER语句。比如：</p>
<p>int SomeFunction(int arg1, int arg2)<br>{<br>&nbsp; UNREFERENCED_PARAMETER(arg2)<br>&nbsp; ...<br>}</p>
<p><br>===============================================================================</p>
<p>&nbsp;&nbsp;&nbsp; [ 翻译文档 本文适合中级读者 已阅读9439次 ]&nbsp;&nbsp; 文档 代码 工具&nbsp;&nbsp; </p>
<p>C++ At Work 专栏...<br>未引用参数，添加任务栏命令及其它...</p>
<p>原著：Paul DiLascia<br>翻译：NorthTibet</p>
<p>下载源代码：CAtWork0505.exe (171KB) <br>原文出处：Unreferenced Parameters, Adding Task Bar Commands, and More </p>
<p>未引用参数<br>添加任务栏命令</p>
<p><br>&nbsp;我看到过一些 C++ 代码针对没有使用过的参数用 UNREFERENCED_PARAMETER，例如：</p>
<p><br>int SomeFunction(int arg1, int arg2)<br>{<br>&nbsp; UNREFERENCED_PARAMETER(arg2)<br>&nbsp; ...<br>}<br>我还看到过这样的代码： <br>int SomeFunction(int arg1, int /* arg2 */)<br>{<br>&nbsp; ...<br>}<br>你能解释它们的差别吗？哪一种用法更好？</p>
<p>Judy McGeough</p>
<p>&nbsp;是啊！为什么呢？让我们从 UNREFERENCED_PARAMETER 开始吧。这个宏在 winnt.h 中定义如下： <br>#define UNREFERENCED_PARAMETER(P) (P)　　换句话说 UNREFERENCED_PARAMETER 展开传递的参数或表达式。其目的是避免编译器关于未引用参数的警告。许多程序员，包括我在内，喜欢用最高级别的警告 Level 4（/W4）进行编译。Level 4 属于&#8220;能被安全忽略的事件&#8221;的范畴。虽然它们可能使你难堪，但很少破坏你的代码。例如，在你的程序中可能会有这样一些代码行：</p>
<p>int x=1;　　但你从没用到过 x。也许这一行是你以前使用 x 时留下来的，只删除了使用它的代码，而忘了删除这个变量。Warning Level 4 能找到这些小麻烦。所以，为什么不让编译器帮助你完成可能是最高级别的专业化呢？用Level 4 编译是展示你工作态度的一种方式。如果你为公众使用者编写库，Level 4 则是社交礼节上需要的。你不想强迫你的开发人员使用低级选项清洁地编译他们的代码。<br>　　问题是，Level 4 实在是太过于注意细节，在 Level 4 上，编译器连未引用参数这样无伤大雅的事情也要抱怨（当然，除非你真的有意使用这个参数，这时便相安无事）。假设你有一个函数带来两个参数，但你只使用其中一个：</p>
<p>int SomeFunction(int arg1, int arg2)<br>{<br>&nbsp;&nbsp;&nbsp; return arg1+5;<br>}使用 /W4，编译器抱怨：</p>
<p>&#8220;warning C4100: ''arg2'' : unreferenced formal parameter.&#8221;为了骗过编译器，你可以加上 UNREFERENCED_PARAMETER(arg2)。现在编译器在编译你的引用 arg2 的函数时便会住口。并且由于语句：</p>
<p>arg2;实际上不做任何事情，编译器不会为之产生任何代码，所以在空间和性能上不会有任何损失。</p>
<p>　　细心的人可能会问：既然你不使用 arg2，那当初为何要声明它呢？通常是因为你实现某个函数以满足某些API固有的署名需要，例如，MFC的 OnSize 处理例程的署名必须要像下面这样：</p>
<p>void OnSize(UINT nType, int cx, int cy);　　这里 cx/cy 是窗口新的宽/高，nType 是一个类似 SIZE_MAXIMIZED 或 SIZE_RESTORED 这样的编码，表示窗口是否最大化或是常规大小。一般你不会在意 nType，只会关注 cx 和 xy。所以如果你想用 /W4，则必须使用 UNREFERENCED_PARAMETER(nType)。OnSize 只是上千个 MFC 和 Windows 函数之一。编写一个基于 Windows 的程序，几乎不可能不碰到未引用参数。<br>　　说了这么多关于 UNREFERENCED_PARAMETER 内容。Judy 在她的问题中还提到了另一个 C++ 程序员常用的并且其作用与 UNREFERENCED_PARAMETER 相同的诀窍，那就是注释函数署名中的参数名：</p>
<p>void CMyWnd::OnSize(UINT /* nType */, <br>int cx, int cy)<br>{<br>}　　现在 nType 是未命名参数，其效果就像你敲入 OnSize(UINT, int cx, int cy)一样。那么现在的关键问题是：你应该使用哪种方法——未命名参数，还是 UNREFERENCED_PARAMETER？<br>　　大多数情况下，两者没什么区别，使用哪一个纯粹是风格问题。（你喜欢你的 java 咖啡是黑色还是奶油的颜色？）但我认为至少有一种情况必须使用 UNREFERENCED_PARAMETER。假设你决定窗口不允许最大化。那么你便禁用 Maximize 按钮，从系统菜单中删除，同时阻止每一个用户能够最大化窗口的操作。因为你是偏执狂（大多数好的程序员都是偏执狂），你添加一个 ASSERT （断言）以确保代码按照你的意图运行：</p>
<p>void CMyWnd::OnSize(UINT nType, int cx, int cy)<br>{<br>&nbsp;&nbsp;&nbsp; ASSERT(nType != SIZE_MAXIMIZE);<br>&nbsp;&nbsp;&nbsp; ... // use cx, cy<br>}　　质检团队竭尽所能以各种方式运行你的程序，ASSERT 从没有弹出过，于是你认为编译生成 Release 版本是安全的。但是此时 _DEBUG 定义没有了，ASSERT(nType != SIZE_MAXIMIZE)展开为 ((void)0)，并且 nType 一下子成了一个未引用参数！这样进入你干净的编译。你无法注释掉参数表中的 nType，因为你要在 ASSERT 中使用它。于是在这种情况下——你唯一使用参数的地方是在 ASSERT 中或其它 _DEBUG 条件代码中——只有 UNREFERENCED_PARAMETER 会保持编译器在 Debug 和 Release 生成模式下都没有问题。知道了吗？<br>　　结束讨论之前，我想还有一个问题我没有提及，就是你可以象下面这样用 pragma 指令抑制单一的编译器警告：</p>
<p>#pragma warning( disable : 4100 )4100 是未引用参数的出错代码。pragma 抑制其余文件/模块的该警告。用下面方法可以重新启用这个警告：</p>
<p>#pragma warning( default : 4100 )　　不管怎样，较好的方法是在禁用特定的警告之前保存所有的警告状态，然后，等你做完之后再回到以前的配置。那样，你便回到的以前的状态，这个状态不一定是编译器的默认状态。<br>　　所以你能象下面这样在代码的前后用 pragma 指令抑制单个函数的未引用参数警告：</p>
<p>#pragma warning( push ) <br>#pragma warning( disable : 4100 )<br>void SomeFunction(...)<br>{<br>}<br>#pragma warning( pop )　　当然，对于未引用参数而言，这种方法未免冗长，但对于其它类型的警告来说可能就不是这样了。库生成者都是用 #pragma warning 来阻塞警告，这样他们的代码可以用 /W4 进行清洁编译。MFC 中充满了这样的 pragmas 指令。还有好多的 #pragma warning 选项我没有在本文讨论。有关它们的信息请参考相关文档。</p>
<p><br>&nbsp;我注意到一些应用程序，当右键单击其任务栏最小化按钮时，在弹出的上下文菜单中具备特殊的命令。例如，WinAmp（一个流行的媒体播放器）有一个附加的 &#8220;WinAmp&#8221;菜单项，其中是 WinAmp 特有的命令。我如何在程序的任务栏按钮中添加我自己的菜单项？</p>
<p><br>Jirair Osygian</p>
<p>&nbsp;我创建了一个简单的 MFC SDI 程序，该程序用表单视图（Form View）显示一个计数器。我想通过右键单击任务栏上程序的最小化按钮来控制启动/停止这个计数器。在表单视图上通过按钮控制的启动/停止功能运行正常，我也能将启动/停止命令加到系统菜单。但我单击加入的系统菜单时没反应。我如何处理这些定制的系统菜单消息？</p>
<p>Monicque Sharman<br>&nbsp;我两个问题一起回答，Jirair 问题的答案很简单：当你右键单击任务栏上应用程序的最小化按钮时，用户看到的菜单与用户单击左上角应用程序标题栏图标或按 Alt+Space 所看到的菜单一样。如 Figure 1 所示。这个菜单被称为系统菜单，其中包括命令如：还原、最小化、最大化和关闭等。</p>
<p><br>Figure 1 系统菜单</p>
<p>　　你可以调用 ::GetSystemMenu 来获得此系统菜单，然后可以添加、删除或修改菜单项。你甚至可以通过关掉 WS_SYSMENU 窗口创建式样标志或 PreCreateWindow 虚函数来完全屏蔽掉这个系统菜单。但不论你做什么，当用户右键单击任务栏上应用程序的最小化按钮时，这个系统菜单还是会显示出来的。<br>　　到了 Monicque 的问题：如果在系统菜单中添加自己的命令，MFC 是如何处理它们的呢？如果按常规来做 ——在某个地方写一个 ON_COMMAND 处理器并将它加到消息映射中，你会发现你的处理器不起作用，怎么会这样呢？<br>　　那是因为 Windows 和 MFC 处理系统命令的方式与处理普通菜单命令的方式不一样。当用户调用窗体中的常规菜单命令或按钮时，Windows 向主窗口发送一个 WM_COMMAND 消息。如果你使用 MFC，那么其命令路由机制将捕获此消息并通过操作系统将它路由到该命令的 ON_COMMAND 命令处理器对象。（有关 MFC 命令处理机制的详细内容，参见我在 MSJ 1995年7月发表的文章：&#8220;Meandering Through the Maze of MFC Message and Command Routing&#8221;）。<br>　　然而系统命令不属于 WM_COMMAND 消息范围。而属于另外一个叫做——WM_SYSCOMMAND 的消息。不论命令ID是真正的系统命令如 SC_MINIMIZE 和 SC_CLOSE，还是你自己添加的其它命令ID都是如此。为了处理系统菜单命令，你必须处理显式处理 WM_SYSCOMMAND 并且要选择你自己的命令 IDs。这就需要你在主窗口消息映射中添加ON_WM_SYSCOMMAND，它有一个处理函数如下： <br>CMainFrame::OnSysCommand(UINT nID, LPARAM lp)<br>{<br>&nbsp;&nbsp;&nbsp; if (nID==ID_MY_COMMAND) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... // 处理它<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; // 传递到基类：这一步很重要!<br>&nbsp;&nbsp;&nbsp; return CFrameWnd::OnSysCommand(nID, lp);<br>}　　如果该命令不是你的，不要忘了将它传递到你的基类处理——典型地，那就是 CFrameWnd 或 CMDIFrameWnd。否则，Windows 将无法得到此消息，并且会破坏内建的命令。<br>　　在主框架中处理 WM_SYSCOMMAND 固然可以，但这样做感觉太业余。为什么要用特殊的机制来处理呢？就因为它们是系统菜单吗？如果你想在视图或文档对象中处理系统命令会怎样呢？有一个常见的命令放到了系统菜单中，它就是&#8220;关于&#8221;（ID_APP_ABOUT），大多数 MFC 程序都是在应用程序对象中处理 ID_APP_ABOUT：</p>
<p>void CMyApp::OnAppAbout()<br>{<br>&nbsp;&nbsp;&nbsp; static CAboutDialog dlg;<br>&nbsp;&nbsp;&nbsp; dlg.DoModal(); <br>}　　MFC 一个真正很酷的特性是它的命令路由系统，它使得象 CMyApp 这样的非窗口对象也能处理菜单命令。许多程序员甚至都不了解怎么会有这样的例外。如果你已经在应用程序对象中处理 ID_APP_ABOUT，那把ID_APP_ABOUT 添加到系统菜单后，为什么还要去实现一套单独的机制？<br>　　处理外加系统命令的比较好的，或者说更 MFC 的方法应该是通过常规的命令路由机制传递它们。然后按 MFC 常规方法编写 ON_COMMAND 处理例程来处理系统命令。你甚至可以用 ON_UPDATE_COMMAND_UI 来更新你的系统菜单项，例如禁用某个菜单项或在菜单项旁边显示一个检讫标志。<br>　　Figure 2 是我写的一个类，CSysCmdRouter，这个类将系统命令转成常规命令。为了使用这个类，你要做的只是在主框架中实例化 CSysCmdRouter，并从 OnCreate 中调用其 Init 方法即可：</p>
<p>int CMainFrame::OnCreate(...)<br>{<br>&nbsp;&nbsp;&nbsp; // 将我的菜单项添加到系统菜单<br>&nbsp;&nbsp;&nbsp; CMenu* pMenu = GetSystemMenu(FALSE);<br>&nbsp;&nbsp;&nbsp; pMenu-&gt;AppendMenu(..ID_MYCMD1..);<br>&nbsp;&nbsp;&nbsp; pMenu-&gt;AppendMenu(..ID_MYCMD2..);</p>
<p>&nbsp;&nbsp;&nbsp; // 通过 MFC 路由系统命令<br>&nbsp;&nbsp;&nbsp; m_sysCmdHook.Init(this);<br>&nbsp;&nbsp;&nbsp; return 0;<br>}　　一旦你调用 CSysCmdRouter::Init，你便可以按常规方式处理 ID_MYCMD1 和 ID_MYCMD2，为 MFC 命令路由机制中的任何对象编写 ON_COMMAND 处理例程——视图，文档，框架，应用程序或通过改写 OnCmdMsg 添加的任何其它命令对象。CSysCmdRouter 还让你用 ON_UPDATE_COMMAND_UI 处理器更新系统菜单。唯一要注意的是确保命令IDs不要与其它菜单命令（除非他们确实代表相同的命令）或内建系统命令发生冲突，内建系统命令从 SC_SIZE = 0xF000 开始。Visual Studio .NET 指定的命令 IDs 从 0x8000 = 32768 开始，所以如果你让 Visual Studio 来指定 IDs，只要不超过 0xF000-0x8000 = 0x7000 个命令即可。也就是十进制的 28,762。如果你的应用程序有超过 28000 个命令，那么你需要咨询编程精神病专家。<br>　　CSysCmdRouter 是如何实现其魔法的呢？简单：它使用我那个以前专栏中无处不在的 CSubclassWnd。CSubclassWnd 使你不用从其派生便能子类化 MFC 窗口对象。CSysCmdRouter 派生自 CSubclassWnd 并使用它子类化主框架。尤其是它截获发送到框架的 WM_SYSCOMMAND 消息。如果命令 ID 属于系统命令（大于 SC_SIZE = 0xF000），则 CSysCmdRouter 沿着 Windows 一路传递该消息；否则便吃掉 WM_SYSCOMMAND 并重新将它作为 WM_COMMAND 发送，于是 MFC 按照其常规路由过程，调用你的 ON_COMMAND 处理器。很聪明，是不是？<br>　　那么 ON_UPDATE_COMMAND_UI 处理器呢？CSysCmdRouter 是如何让它处理系统菜单命令的呢？很简单。就在 Windows 显示菜单前，他向你的主窗口发送一个 WM_INITMENUPOPUP 消息。这是你更新菜单项的最佳时机——启用或禁用它们，添加检讫标志等等。MFC 为每个菜单项创建一个 CCmdUI 对象并将它传递到你的消息映射中相应的 ON_UPDATE_COMMAND_UI 处理器。以它为参数的 MFC 函数是 CFrameWnd::OnInitMenuPopup，这个函数是这样的：</p>
<p>void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)<br>{<br>&nbsp;&nbsp;&nbsp; if (bSysMenu)<br>&nbsp;&nbsp;&nbsp; return; // don''t support system menu<br>&nbsp;&nbsp;&nbsp; ...<br>}　　MFC 初始化系统菜单时不做任何事情。为什么要去关心这种事呢？万一你要让 bSysMenu 为 FALSE，即使是系统菜单，那该怎么办？这恰恰是 CSysCmdRouter 做的事情。它截取 WM_INITMENUPOPUP 并清除 bSysMenu 标志，也就是 LPARAM 的 HIWORD：</p>
<p>if (msg==WM_INITMENUPOPUP) {<br>&nbsp;&nbsp;&nbsp; lp = LOWORD(lp); // (set HIWORD = 0)<br>}　　现在，当 MFC 获得 WM_INITMENUPOPUP，它认为该菜单是常规菜单。只要你的命令 IDs 与真正的系统菜单不冲突，一切都运行得很好。如果你改写 OnInitMenuPopup，唯一丢失的东西是不能从主窗口菜单中区分系统菜单。嘿，你不能什么都想要！通过改写 CWnd::WindowProc，你总是能处理 WM_INITMENUPOPUP 的，或你想要区分，就比较 HMENUs。但你确实不用关心命令来自何处。</p>
<p><br>Figure 3 任务栏菜单</p>
<p>　　为了展示所有的实践，我写了一个小测试程序： TBMenu。如图 Figure 3 所示，当你右键单击任务栏上 TBMenu 的最小化按钮，便会显示出菜单。你可以看到在菜单底部有两个额外的命令。TBMenu 的 CMainFrame代码如 Figure 4 所示。便知道在 OnCreate 的什么地方添加命令并在 CMainFrame 的消息映射中用 ON_COMMAND 以及 ON_UPDATE_COMMAND_UI 处理器处理它们。TBMenu 在其应用程序类中处理 ID_APP_ABOUT（代码未列出）。CSysCmdRouter 使系统命令的工作机制类似其它命令。</p>
<p><br>说到命令，我们来看看一个小资料：</p>
<p>　　在我一月份的专栏中，我问是否有人知道 Ctrl+Alt+Del 的由来。显然，有几个读者知道如何使用 Google，因为他们发给我的是相同的链接：《今日美国》上的一篇文章：&#8220;Thank this guy for 'control-alt-delete'&#8221;，我在一月发问之前就发现了这篇文章。Ctrl+Alt+Del 是由一个名叫 David J. Bradley 的人发现的，他在 IBM 工作过。<br>IBM 觉得应该有一种方法不用关闭电源就能重置（reset）其新的 PC 机。为什么要专门用 Ctrl+Alt+Del 这三个键呢？从技术上来说，David 需要使用两个修饰键。他想要一种没有人可能意外敲入的键组合。所以他选择了 <br>Ctrl+Alt 作为修饰键（比 Shift 用得少）和 Delete，此键位于键盘的另一端，所以敲击 Ctrl+Alt+Del 需要两只手，至少在过去是这样做的。<br>当今现代键盘在右边也有 Ctrl 和 Alt 键。重启特性的初衷是为 IBM 的人设计的秘密安全出口，但不可避免地，它已经成为一个不是秘密的秘密。一旦开发人员知道了它，他们便开始告诉客户使用这个特性来解决机器挂起问题。随着历史的发展，Ctrl+Alt+Del 被人们亲切地成为&#8220;三指敬礼&#8221;，即便是在当今的 Windows 中仍然具有生命力，用它调出任务管理器，以便你能杀死挂起的任务或终止系统（更多有关类似 Ctrl+Alt+Del 安全键序列的内容，参见本月的 Security Briefs 专栏）。那么，如果 Ctrl+Alt+Del 失败了怎么办？为什么会失败，请按住它保持 5 秒钟。<br>　　David Bradley 是当初建立 IBM 个人计算机的 12 个工程师之一。他编写了 ROM BIOS，有关 David 的简介，参见 David J. Bradley。</p>
<p>祝编程愉快！</p>
<p>您的提问和评论可发送到 Paul 的信箱：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#99;&#112;&#112;&#113;&#97;&#64;&#109;&#105;&#99;&#114;&#111;&#115;&#111;&#102;&#116;&#46;&#99;&#111;&#109;">cppqa@microsoft.com</a><br>　<br>&nbsp;<br>&nbsp;作者简介<br>　　Paul DiLascia 是一名自由作家，顾问和 Web/UI 设计者。他是《Writing Reusable Windows Code in C++》书（Addison-Wesley, 1992）的作者。通过 <a href="http://www.dilascia.com/">http://www.dilascia.com</a> 可以获得更多了解。 　 <br>本文出自 MSDN Magazine 的 May 2005 期刊，可通过当地报摊获得，或者最好是 订阅 <br>&nbsp;</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/liuchanghe/archive/2006/12/31/1471302.aspx">http://blog.csdn.net/liuchanghe/archive/2006/12/31/1471302.aspx</a></p>
<p><a href="http://blog.csdn.net/liuchanghe/archive/2006/12/31/1471302.aspx"></a>&nbsp;</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/113526.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-04-25 19:24 <a href="http://www.cppblog.com/tdweng/articles/113526.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sscanf()的一些使用说明 </title><link>http://www.cppblog.com/tdweng/articles/113495.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Sun, 25 Apr 2010 02:47:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/113495.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/113495.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/113495.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/113495.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/113495.html</trackback:ping><description><![CDATA[<div class=postText>
<div>这里有些sscanf()的一些使用说明，都是从论坛，Blog里整理出来的。供大家使用。<br>&nbsp;&nbsp; 通过学习和使用个人认为，在字符串格式不是很复杂，但是也并不简单的时候用这个函数比较合适，这个尺度就要靠自己把握了，字符串不是很复杂，但自己写个处理的函数比较麻烦，效率也不高，就用这个函数，如果字符串很复杂，那就用正则表达式吧。<br>不多说了，看看下面这些介绍和列子吧！</div>
<div>名称:sscanf() - 从一个字符串中读进与指定格式相符的数据.<br>函数原型:<br>Int&nbsp; sscanf( string str, string fmt, mixed var1, mixed var2 ... );<br>int&nbsp; scanf( const char *format [,argument]... );</div>
<div>说明：<br>sscanf与scanf类似，都是用于输入的，只是后者以屏幕(stdin)为输入源，前者以固定字符串为输入源。<br>其中的format可以是一个或多个 {%[*] [width] [{h | l | I64 | L}]type | ' ' | '\t' | '\n' | 非%符号}</div>
<div>支持集合操作：<br>&nbsp;&nbsp;&nbsp;&nbsp; %[a-z] 表示匹配a到z中任意字符，贪婪性(尽可能多的匹配)<br>&nbsp;&nbsp;&nbsp;&nbsp; %[aB'] 匹配a、B、'中一员，贪婪性<br>&nbsp;&nbsp;&nbsp;&nbsp; %[^a] 匹配非a的任意字符，贪婪性</div>
<div>例子：<br>1. 常见用法。<br>&nbsp;&nbsp;&nbsp; char buf[512] = {0};<br>&nbsp;&nbsp;&nbsp; sscanf("123456 ", "%s", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：123456</div>
<div>2. 取指定长度的字符串。如在下例中，取最大长度为4字节的字符串。<br>&nbsp;&nbsp;&nbsp; sscanf("123456 ", "%4s", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：1234</div>
<div>3. 取到指定字符为止的字符串。如在下例中，取遇到空格为止字符串。<br>&nbsp;&nbsp;&nbsp; sscanf("123456 abcdedf", "%[^ ]", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：123456<br>&nbsp;<br>4.&nbsp; 取仅包含指定字符集的字符串。如在下例中，取仅包含1到9和小写字母的字符串。<br>&nbsp;&nbsp;&nbsp; sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：123456abcdedf<br>&nbsp;<br>5.&nbsp; 取到指定字符集为止的字符串。如在下例中，取遇到大写字母为止的字符串。<br>&nbsp;&nbsp;&nbsp; sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：123456abcdedf</div>
<div>6、给定一个字符串<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#105;&#105;&#111;&#115;&#47;&#49;&#50;&#68;&#68;&#87;&#68;&#70;&#70;&#64;&#49;&#50;&#50;"><u><font color=#0000ff size=2>iios/12DDWDFF@122</font></u></a>，获取 / 和 @ 之间的字符串，先将 "iios/"过滤掉，再将非<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#64;&#39;"><u><font color=#0000ff size=2>'@'</font></u></a>的一串内容送到buf中<br>&nbsp;&nbsp;&nbsp; sscanf("<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#105;&#105;&#111;&#115;&#47;&#49;&#50;&#68;&#68;&#87;&#68;&#70;&#70;&#64;&#49;&#50;&#50;"><u><font color=#0000ff size=2>iios/12DDWDFF@122</font></u></a>", "%*[^/]/%[^@]", buf);<br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：12DDWDFF<br>&nbsp;<br>7、给定一个字符串&#8220;&#8220;hello, world&#8221;，仅保留world。（注意：&#8220;，&#8221;之后有一空格）</div>
<div>&nbsp;&nbsp;&nbsp; sscanf(&#8220;hello, world&#8221;,&nbsp; "%*s%s",&nbsp; buf);&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; printf("%s\n", buf);<br>结果为：world<br>%*s表示第一个匹配到的%s被过滤掉，即hello被过滤了<br>如果没有空格则结果为NULL。<br>8、<br>&nbsp;char *s="1try234delete5"&nbsp; <br>则： <br>sscanf(s, "1%[^2]234%[^5]", s1, s2); <br>scanf的format中出现的非转换字符（%之前或转换字符之后的字符），即此例中的1234用来跳过输入中的相应字符； <br>&#8216;[]&#8217;的含义与正则表达式中相同，表示匹配其中出现的字符序列；^表示相反。使用[ ]时接收输入的变量必须是有足够存储空间的char、signed char、unsigned char数组。记住[也是转换字符，所以没有s了。</div>
<div>8、分割以某字符标记的字符串。</div>
<div>&nbsp;char test[]="222,333,444,,,555,666"; <br>&nbsp;char s1[4],s2[4],s3[4],s4[4],s5[4],s6[4],s7[4]; <br>&nbsp;sscanf(test,"%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]",s1,s2,s3,s4,s5,s6,s7); <br>&nbsp;printf("sssa1=%s",s1); <br>&nbsp;printf("sssa2=%s",s2); <br>&nbsp;printf("sssa3=%s",s3); <br>&nbsp;printf("sssa4=%s",s4); <br>&nbsp;printf("sssa5=%s",s5); <br>&nbsp;printf("sssa6=%s",s6); <br>&nbsp;printf("sssa7=%s",s7); <br>9、一个提取用户个人资料中邮件地址的例子 <br>#include&lt;cstdlib&gt;<br>#include&lt;cstdio&gt;<br>using namespace std;<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; char a[20]={0};<br>&nbsp;&nbsp;&nbsp; char b[20]={0};<br>&nbsp;&nbsp;&nbsp; //假设email地址信息以';'结束 <br>&nbsp;&nbsp;&nbsp; sscanf("email:jimmywhr@gmail.com;","%*[^:]:%[^;]",a);<br>&nbsp;&nbsp;&nbsp; //假设email地址信息没有特定的结束标志 <br>&nbsp;&nbsp;&nbsp; sscanf("email:jimmywhr@gmail.com","%*[^:]:%s",b);<br>&nbsp;&nbsp;&nbsp; printf("%s\n",a);<br>&nbsp;&nbsp;&nbsp; printf("%s\n",b);<br>&nbsp;&nbsp;&nbsp; system("pause");<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br>&nbsp; 关键是"%*[^:]:%[^;]"和"%*[^:]:%s"这两个参数的问题 <br>&nbsp; %*[^:]&nbsp;&nbsp;&nbsp; 表示满足"[]"里的条件将被过滤掉，不会向目标参数中写入值。这里的意思是在<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一个':'之前的字符会在写入时过滤掉,'^'是表示否定的意思，整个参数翻译<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 成白话就是：将在遇到第一个':'之前的（不为':'的）字符全部过滤掉。 <br>&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自然就是跳过':'的意思。<br>&nbsp; %[^;]&nbsp;&nbsp;&nbsp;&nbsp; 拷贝字符直到遇到';'。</div>
<div>一下摘自：<a href="http://blog.csdn.net/lbird/archive/2007/08/03/1724429.aspx"><u><font color=#810081 size=2>http://blog.csdn.net/lbird/archive/2007/08/03/1724429.aspx</font></u></a><br>%[ ] 的用法：%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是&#8221;^&#8221;，则表示反意思。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ ]内的字符串可以是1或更多字符组成。空字符集（%[]）是违反规定的，可</div>
<div>&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;&nbsp;&nbsp;&nbsp; </div>
<div>%[a-z] 读取在 a-z 之间的字符串，如果不在此之前则停止，如</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char s[]="hello, my friend&#8221; ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 注意: ,逗号在不 a-z之间</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sscanf( s, &#8220;%[a-z]&#8221;, string ) ; // string=hello</div>
<div><br>%[^a-z] 读取不在 a-z 之间的字符串，如果碰到a-z之间的字符则停止，如</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char s[]="HELLOkitty&#8221; ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 注意: ,逗号在不 a-z之间</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sscanf( s, &#8220;%[^a-z]&#8221;, string ) ; // string=HELLO</div>
<div><br>%*[^=]&nbsp;&nbsp;&nbsp; 前面带 * 号表示不保存变量。跳过符合条件的字符串。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char s[]="notepad=1.0.0.1001" ;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char szfilename [32] = "" ;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = sscanf( s, "%*[^=]", szfilename ) ; // szfilename=NULL,因为没保存</div>
<div>&nbsp;int i = sscanf( s, "%*[^=]=%s", szfilename ) ; // szfilename=1.0.0.1001</div>
<div>%40c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 读取40个字符</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The run-time</div>
<div>&nbsp;library does not automatically append a null terminator</div>
<div>&nbsp;to the string, nor does reading 40 characters</div>
<div>&nbsp;automatically terminate the scanf() function. Because the</div>
<div>&nbsp;library uses buffered input, you must press the ENTER key</div>
<div>&nbsp;to terminate the string scan. If you press the ENTER before</div>
<div>&nbsp;the scanf() reads 40 characters, it is displayed normally,</div>
<div>&nbsp;and the library continues to prompt for additional input</div>
<div>&nbsp;until it reads 40 characters</div>
<div><br>%[^=]&nbsp;&nbsp;&nbsp;&nbsp; 读取字符串直到碰到&#8217;=&#8217;号，&#8217;^&#8217;后面可以带更多字符,如：</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char s[]="notepad=1.0.0.1001" ;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char szfilename [32] = "" ;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = sscanf( s, "%[^=]", szfilename ) ; // szfilename=notepad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果参数格式是：%[^=:] ，那么也可以从 notepad:1.0.0.1001读取notepad</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </div>
<div>使用例子：</div>
<div>&nbsp;char s[]="notepad=1.0.0.1001" ;</div>
<div>&nbsp;char szname [32] = "" ;</div>
<div>&nbsp;char szver [32] = &#8220;&#8221; ;</div>
<div>sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001</div>
<div>总结：%[]有很大的功能，但是并不是很常用到，主要因为：</div>
<div>1、许多系统的 scanf 函数都有漏洞. (典型的就是 TC 在输入浮点型时有时会出错). </div>
<div>2、用法复杂, 容易出错. </div>
<div>3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率.</div>
<div>个人觉得第3点最致命，越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。</div>
</div>
<p>以前只是简单是使用sscanf,却没发现其还有如此强大的功能<br>&nbsp;char str0[100],str1[100],str2[100],str3[100];<br><br>&nbsp;sscanf("abcde abc 123 aaa","%s %s %s %s",str0,str1,str2,str3);<br>&nbsp;结果:str0="abcde"&nbsp;&nbsp; str1="abc"&nbsp; str2 = "123" str3="aaa"<br><br>&nbsp;sscanf("abcde abc 123 aaa","abc%s %s %*d %s",str0,str1,str3);<br>&nbsp;结果:str0="abcde"&nbsp;&nbsp; str1="abc"&nbsp; str3="aaa"<br><br>&nbsp;sscanf("abc123 efg456","%4s",str0);<br>&nbsp;结果:str0="abc1"&nbsp;&nbsp;&nbsp;<br><br>&nbsp;sscanf("abc123 efg456a4","%[a-z 1-5]",str0);<br>&nbsp;结果:str0="abc123 efg45"&nbsp;&nbsp;&nbsp;<br><br>sscanf("abc123 efg456a4","%[a-z1-5]",str0);<br>&nbsp;结果:str0="abc123"&nbsp;<br><br>&nbsp;sscanf("ABCTabcZ123 efg456","%[A-P]",str0);<br>&nbsp;结果:str0="ABC"&nbsp;&nbsp;&nbsp;<br><br>&nbsp;sscanf("abc 12345","%[^ ]",str0);<br>&nbsp;结果:str0="abc"&nbsp;&nbsp;&nbsp;<br><br>&nbsp;sscanf("abc 12345","%[^4]",str0);<br>&nbsp;结果:str0="abc 123"&nbsp;&nbsp;&nbsp;<br><br>&nbsp;sscanf("fdaBs 52aB1asdf","%[^4-0]",str0);<br>&nbsp;结果:str0="fdaBs 5"&nbsp;&nbsp;&nbsp;<br><br>&nbsp;sscanf("abc 12345","%[^ ]%[^3]",str0,str1);<br>&nbsp;结果:str0="abc"&nbsp;&nbsp;&nbsp;&nbsp;str1="12"<br><br>&nbsp;sscanf("abc301abc2345","%*[^9-0]%s",str0);&nbsp;<br>&nbsp;结果:str0="301abc2345"&nbsp;&nbsp;&nbsp;<br>&nbsp;sscanf("<a href='&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#99;&#97;&#64;&#49;&#50;&#51;&#101;&#102;&#103;&#52;&#64;&#53;&#97;&#98;&#99;&#34;&#44;&#34;&#37;&#42;&#91;&#94;&#64;&#93;&#64;&#37;&#91;&#94;&#64;&#93;&#34;&#44;&#115;&#116;&#114;&#48;'><u><font color=#0000ff>bca@123efg4@5abc","%*[^@]@%[^@]",str0</font></u></a>);<br>&nbsp;结果:str0="<u><font color=#0000ff>123efg4</font></u>"&nbsp;&nbsp;&nbsp;</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/113495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-04-25 10:47 <a href="http://www.cppblog.com/tdweng/articles/113495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 运算符优先级列表 </title><link>http://www.cppblog.com/tdweng/articles/113486.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Sat, 24 Apr 2010 18:13:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/113486.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/113486.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/113486.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/113486.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/113486.html</trackback:ping><description><![CDATA[<h2><a id=viewpost1_TitleUrl href="http://www.cppblog.com/aqazero/archive/2006/06/08/8284.html"><u><font color=#0000ff>C++ 运算符优先级列表</font></u></a> </h2>
<a href="http://www.cppreference.com/operator_precedence.html"><u><font color=#0000ff>http://www.cppreference.com/operator_precedence.html</font></u></a> <br>
<table class=code-table border=1>
    <tbody>
        <tr>
            <th class=code-table-th>Precedence</th>
            <th class=code-table-th>Operator</th>
            <th class=code-table-th>Description</th>
            <th class=code-table-th>Example</th>
            <th class=code-table-th>Associativity</th>
        </tr>
        <tr>
            <td class=code-table-td>1</td>
            <td class=code-table-td>()<br>[]<br>-&gt;<br>.<br>::<br>++<br>--</td>
            <td class=code-table-td>Grouping operator<br>Array access<br>Member access from a pointer<br>Member access from an object<br>Scoping operator<br>Post-increment<br>Post-decrement</td>
            <td class=code-table-td>(a + b) / 4;<br>array[4] = 2;<br>ptr-&gt;age = 34;<br>obj.age = 34;<br>Class::age = 2;<br>for( i = 0; i &lt; 10; i++ ) ...<br>for( i = 10; i &gt; 0; i-- ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>2</td>
            <td class=code-table-td>!<br>~<br>++<br>--<br>-<br>+<br>*<br>&amp;<br>(type)<br><a href="http://www.cppreference.com/keywords/sizeof.html"><u><font color=#0000ff>sizeof</font></u></a></td>
            <td class=code-table-td>Logical negation<br>Bitwise complement<br>Pre-increment<br>Pre-decrement<br>Unary minus<br>Unary plus<br>Dereference<br>Address of<br>Cast to a given type<br>Return size in bytes</td>
            <td class=code-table-td>if( !done ) ...<br>flags = ~flags;<br>for( i = 0; i &lt; 10; ++i ) ...<br>for( i = 10; i &gt; 0; --i ) ...<br>int i = -1;<br>int i = +1;<br>data = *ptr;<br>address = &amp;obj;<br>int i = (int) floatNum;<br>int size = sizeof(floatNum);</td>
            <td class=code-table-td>right to left</td>
        </tr>
        <tr>
            <td class=code-table-td>3</td>
            <td class=code-table-td>-&gt;*<br>.*</td>
            <td class=code-table-td>Member pointer selector<br>Member pointer selector</td>
            <td class=code-table-td>ptr-&gt;*var = 24;<br>obj.*var = 24;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>4</td>
            <td class=code-table-td>*<br>/<br>%</td>
            <td class=code-table-td>Multiplication<br>Division<br>Modulus</td>
            <td class=code-table-td>int i = 2 * 4;<br>float f = 10 / 3;<br>int rem = 4 % 3;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>5</td>
            <td class=code-table-td>+<br>-</td>
            <td class=code-table-td>Addition<br>Subtraction</td>
            <td class=code-table-td>int i = 2 + 3;<br>int i = 5 - 1;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>6</td>
            <td class=code-table-td>&lt;&lt;<br>&gt;&gt;</td>
            <td class=code-table-td>Bitwise shift left<br>Bitwise shift right</td>
            <td class=code-table-td>int flags = 33 &lt;&lt; 1;<br>int flags = 33 &gt;&gt; 1;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>7</td>
            <td class=code-table-td>&lt;<br>&lt;=<br>&gt;<br>&gt;=</td>
            <td class=code-table-td>Comparison less-than<br>Comparison less-than-or-equal-to<br>Comparison greater-than<br>Comparison geater-than-or-equal-to</td>
            <td class=code-table-td>if( i &lt; 42 ) ...<br>if( i &lt;= 42 ) ...<br>if( i &gt; 42 ) ...<br>if( i &gt;= 42 ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>8</td>
            <td class=code-table-td>==<br>!=</td>
            <td class=code-table-td>Comparison equal-to<br>Comparison not-equal-to</td>
            <td class=code-table-td>if( i == 42 ) ...<br>if( i != 42 ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>9</td>
            <td class=code-table-td>&amp;</td>
            <td class=code-table-td>Bitwise AND</td>
            <td class=code-table-td>flags = flags &amp; 42;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>10</td>
            <td class=code-table-td>^</td>
            <td class=code-table-td>Bitwise exclusive OR</td>
            <td class=code-table-td>flags = flags ^ 42;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>11</td>
            <td class=code-table-td>|</td>
            <td class=code-table-td>Bitwise inclusive (normal) OR</td>
            <td class=code-table-td>flags = flags | 42;</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>12</td>
            <td class=code-table-td>&amp;&amp;</td>
            <td class=code-table-td>Logical AND</td>
            <td class=code-table-td>if( conditionA &amp;&amp; conditionB ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>13</td>
            <td class=code-table-td>||</td>
            <td class=code-table-td>Logical OR</td>
            <td class=code-table-td>if( conditionA || conditionB ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
        <tr>
            <td class=code-table-td>14</td>
            <td class=code-table-td>? :</td>
            <td class=code-table-td>Ternary conditional (if-then-else)</td>
            <td class=code-table-td>int i = (a &gt; b) ? a : b;</td>
            <td class=code-table-td>right to left</td>
        </tr>
        <tr>
            <td class=code-table-td>15</td>
            <td class=code-table-td>=<br>+=<br>-=<br>*=<br>/=<br>%=<br>&amp;=<br>^=<br>|=<br>&lt;&lt;=<br>&gt;&gt;=</td>
            <td class=code-table-td>Assignment operator<br>Increment and assign<br>Decrement and assign<br>Multiply and assign<br>Divide and assign<br>Modulo and assign<br>Bitwise AND and assign<br>Bitwise exclusive OR and assign<br>Bitwise inclusive (normal) OR and assign<br>Bitwise shift left and assign<br>Bitwise shift right and assign</td>
            <td class=code-table-td>int a = b;<br>a += 3;<br>b -= 4;<br>a *= 5;<br>a /= 2;<br>a %= 3;<br>flags &amp;= new_flags;<br>flags ^= new_flags;<br>flags |= new_flags;<br>flags &lt;&lt;= 2;<br>flags &gt;&gt;= 2;</td>
            <td class=code-table-td>right to left</td>
        </tr>
        <tr>
            <td class=code-table-td>16</td>
            <td class=code-table-td>,</td>
            <td class=code-table-td>Sequential evaluation operator</td>
            <td class=code-table-td>for( i = 0, j = 0; i &lt; 10; i++, j++ ) ...</td>
            <td class=code-table-td>left to right</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/tdweng/aggbug/113486.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2010-04-25 02:13 <a href="http://www.cppblog.com/tdweng/articles/113486.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>