﻿<?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/deane/</link><description>                    追逐梦想，永不停步......</description><language>zh-cn</language><lastBuildDate>Fri, 17 Apr 2026 10:04:23 GMT</lastBuildDate><pubDate>Fri, 17 Apr 2026 10:04:23 GMT</pubDate><ttl>60</ttl><item><title>对C++ Local的经典分析(转)</title><link>http://www.cppblog.com/deane/archive/2011/08/11/153007.html</link><dc:creator>李阳</dc:creator><author>李阳</author><pubDate>Wed, 10 Aug 2011 16:08:00 GMT</pubDate><guid>http://www.cppblog.com/deane/archive/2011/08/11/153007.html</guid><wfw:comment>http://www.cppblog.com/deane/comments/153007.html</wfw:comment><comments>http://www.cppblog.com/deane/archive/2011/08/11/153007.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/deane/comments/commentRss/153007.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deane/services/trackbacks/153007.html</trackback:ping><description><![CDATA[<div> <div id="wrapper"> 	<div id="header"></div> 	<div id="main">		<div id="container"> 			<div id="content" role="main"> 							<div id="post-86" post="" type-post="" status-publish="" format-standard="" hentry="" category-logs="" category-reprinted="" tag-c="" tag-locale=""> 				<div> 					<h2>对C++ Local的经典分析</h2></div>	 					<div> 					<p>本贴转载自：<a href="../../lf426/" target="\&quot;_blank\&quot;">再别流年的技术实验室</a></p> <pre>文章地址：  http://kittsoft.xp3.biz/?p=86<a href="../../lf426/archive/2010/06/26/118788.html" target="\&quot;_blank\&quot;"></a></pre> <br /> <p>&#8220;这个问题比你想象中复杂&#8221;<br /> （我也学下BS的风格，虽然这句话是我自己临时想说的。^^）<br /> 从字符到整数<br /> char是一种整数类型，这句话的含义是，char所能表示的字符在C/C++中都是整数类型。好，接下来，很多文章就会举出一个典型例子，比如，&#8217;a' 的数值就是0&#215;61。这种说法对吗？如果你细心的读过K&amp;R和BS对于C和C++描述的原著，你就会马上反驳道，0&#215;61只是&#8217;a'的ASCII 值，并没有任何规定C/C++的char值必须对应ASCII。C/C++甚至没有规定char占几位，只是规定了sizeof(char)等于1。<br /> 当然，目前大部分情况下，char是8位的，并且，在ASCII范围内的值，与ASCII对应。<br /> 本地化策略集（locale）<br /> &#8220;将&#8217;a'翻译成0&#215;61的整数值&#8221;，&#8220;将ASCII范围内的编码与char的整数值对应起来&#8221;，类似这样的规定，是特定系统和特定编译器制定 的，C/C++中有个特定的名词来描述这种规定的集合：本地化策略集（locale。也有翻译成&#8220;现场&#8221;）。而翻译&#8212;&#8212;也就是代码转换（codecvt） 只是这个集合中的一个，C++中定义为策略（facet。也有翻译为&#8220;刻面&#8221;）<br /> C/C++的编译策略<br /> &#8220;本地化策略集&#8221;是个很好的概念，可惜在字符和字符串这个层面上，C/C++并不使用（C++的locale通常只是影响流（stream）），C/C++使用更直接简单的策略：硬编码。<br /> 简单的说，字符（串）在程序文件（可执行文件，非源文件）中的表示，与在程序执行中在内存中的表示一致。考虑两种情况：<br /> A、char c = 0&#215;61;<br /> B、char c = &#8216;a&#8217;;<br /> 情况A下，编译器可以直接认识作为整数的c，但是在情况B下，编译器必须将&#8217;a'翻译成整数。编译器的策略也很简单，就是直接读取字符（串）在源文件中的编码数值。比如：<br /> const char* s = &#8220;中文abc&#8221;;<br /> 这段字符串在GB2312（Windows 936），也就是我们的windows默认中文系统源文件中的编码为：<br /> 0xD6&nbsp;&nbsp; 0xD0&nbsp;&nbsp; 0xCE 0xC4 0&#215;61 0&#215;62 0&#215;63<br /> 在UTF-8，也就是Linux默认系统源文件中的编码为：<br /> 0xE4&nbsp;&nbsp; 0xB8&nbsp;&nbsp; 0xAD&nbsp;&nbsp; 0xE6&nbsp;&nbsp; 0&#215;96&nbsp;&nbsp; 0&#215;87&nbsp;&nbsp; 0&#215;61&nbsp;&nbsp; 0&#215;62&nbsp;&nbsp; 0&#215;63<br /> 一般情况下，编译器会忠实于源文件的编码为s赋值，例外的情况比如VC会自作聪明的把大部分其他类型编码的字符串转换成GB2312（除了像UTF-8 without signature这样的幸存者）。<br /> 程序在执行的时候，s也就保持是这样的编码，不会再做其他的转换。<br /> 宽字符 wchar_t<br /> 正如char没有规定大小，wchar_t同样没有标准限定，标准只是要求一个wchar_t可以表示任何系统所能认识的字符，在win32 中，wchar_t为16位；Linux中是32位。wchar_t同样没有规定编码，因为Unicode的概念我们后面才解释，所以这里只是提一下，在 win32中，wchar_t的编码是UCS-2BE；而Linux中是UTF-32BE（等价于UCS-4BE），不过简单的说，在16位以内，一个字 符的这3种编码值是一样的。因此：<br /> const wchar_t* ws = L&#8221;中文abc&#8221;;<br /> 的编码分别为：<br /> 0x4E2D&nbsp;&nbsp; 0&#215;6587&nbsp;&nbsp;&nbsp; 0&#215;0061&nbsp;&nbsp; 0&#215;0062&nbsp;&nbsp; 0&#215;0063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //win32，16位<br /> 0x00004E2D&nbsp;&nbsp; 0&#215;00006587&nbsp;&nbsp;&nbsp; 0&#215;00000061&nbsp;&nbsp; 0&#215;00000062&nbsp;&nbsp; 0&#215;00000063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Linux，32位<br /> 大写的L是告诉编译器：这是宽字符串。所以，这时候是需要编译器根据locale来进行翻译的。<br /> 比如，在Windows环境中，编译器的翻译策略是GB2312到UCS-2BE；Linux环境中的策略是UTF-8到UTF-32BE。<br /> 这时候就要求源文件的编码与编译器的本地化策略集中代码翻译的策略一致，例如VC只能读取GB2312的源代码（这里还是例外，VC太自作聪明了  ，会将很多其他代码在编译时自动转换成GB2312），而gcc只能读取UTF-8的源代码（这里就有个尴尬，MinGW运行win32下，所以只有 GB2312系统才认；而MinGW却用gcc编写，所以自己只认UTF-8，所以结果就是，MinGW的宽字符被废掉了）。<br /> 宽字符（串）由编译器翻译，还是被硬编码进程序文件中。</p> <p>Unicode和UCS<br /> Unicode和UCS是两个独立的组织分别制定的一套编码标准，但是因为历史的原因，这两套标准是完全一样的。Unicode这个词用得比较多的原因可 能是因为比较容易记住，如果没有特别的声明，在本文所提及的Unicode和UCS就是一个意思。Unicode的目标是建立一套可以包含人类所有语言文 字符号你想得到想不到的各种东西的编码，其编码容量甚至预留了火星语以及银河系以外语言的空间&#8212;&#8212;开个玩笑，反正简单的说，Unicode编码集足够的 大，如果用计算机单位来表示，其数量比3个字节大一些，不到4个字节。<br /> Unicode和UTF<br /> 因为Unicode包含的内容太多，其编码在计算机中的表示方法就成为了一个有必要研究的问题。传统编码，比如标准的7位ASCII，在计算机中的表示方 法就是占一个字节的后7位，这似乎是不需要解释就符合大家习惯的表示方法。但是当今Unicode的总数达到32位（计算机的最小单位是字节，所以大于3 字节，就只能至少用4字节表示），对于大部分常用字符，比如Unicode编码只占一个字节大小的英语字母，占两个字节大小汉字，都用4个字节来储存太奢 侈了。另外，如果都用4字节直接表示，就不可避免的出现为0的字节。而我们知道，在C语言中，0&#215;00的字节就是&#8217;\0&#8242;，表示的是一个字符串（char 字符串，非wchar_t）的结束，换句话说，C风格的char字符串无法表示Unicode。<br /> 因为类似的种种问题，为Unicode在计算机中的编码方法出现了，这就是UTF；所对应的，为UCS编码实现的方式也有自己的说法。一般来说，UTF- x，x表示这套编码一个单位至少占用x位，因为Unicode最长达到32位，所以UTF-x通常是变长的&#8212;&#8212;除了UTF-32；而UCS-y表示一个单 位就占用y个字节，所以能表示当今Unicode的UCS-y只有UCS-4，但是因为历史的原因，当Unicode还没那么庞大的时候，2个字节足够表 示，所以有UCS-2，现在看来，UCS-2所能表示的Unicode只是当今Unicode的一个子集。<br /> 也就是说，如果某种编码，能根据一定的规则算法，得到Unicode编码，那么这种编码方式就可以称之为UTF。<br /> UTF-8和Windows GB2312<br /> UTF-8是一套&#8220;聪明&#8221;的编码，可能用1，2，3，4个字节表示。通过UTF-8的算法，每一个字节表示的信息都很明确：这是不是某个Unicode编 码的第一个字节；如果是第一个字节，这是一个几位Unicode编码。这种&#8220;聪明&#8221;被称为UTF-8的自我同步，也是UTF-8成为网络传输标准编码的原 因。<br /> 另外，UTF-8也不会出现0字节，所以可以表示为char字符串，所以可以成为系统的编码。Linux系统默认使用UTF-8编码。<br /> Windows GB2312一般自称为GB2312，其实真正的名字应该是Windows Codepage  936，这也是一种变长的编码：1个字节表示传统的ASCII部分；汉字部分是两个字节的GBK（国标扩（展），拼音声母）。Codepage  936也可以表示为char字符串，是中文Windows系统的默认编码。<br /> 我们在第1节中看到的<br /> const char* s = &#8220;中文abc&#8221;;<br /> 在Windows中的编码就是Codepage 936；在Linux中的编码就是UTF-8。<br /> 需要注意的是，Codepage 936不像UTF，跟Unicode没有换算的关系，所以只能通过&#8220;代码页&#8221;技术查表对应。<br /> UTF-16和UCS-2<br /> UTF-16用2个字节或者4个字节表示。在2个字节大小的时候，跟UCS-2是一样的。UTF-16不像UTF-8，没有自我同步机制，所以，编码大位 在前还是小位在前，就成了见仁见智的问题。我们在第1节中，&#8220;中&#8221;的UCS-2BE（因为是两个字节，所以也就是UTF-16BE）编码是0x4E2D， 这里的BE就是大位在后的意思（也就是小位在前了），对应的，如果是UCS-2LE，编码就成了0x2D4E。<br /> Windows中的wchar_t就是采用UCS-2BE编码。需要指出的是，C++标准中对wchar_t的要求是要能表示所有系统能识别的字符。Windows自称支持Unicode，但是其wchar_t却不能表示所有的Unicode，由此违背了C++标准。<br /> UTF-32和UCS-4<br /> UTF-32在目前阶段等价于UCS-4，都用定长的4个字节表示。UTF-32同样存在BE和LE的问题。Linux的wchar_t编码就是UTF- 32BE。在16位以内的时候，UTF-32BE的后两位（前两位是0&#215;00 0&#215;00）等价于UTF-16BE也就等价于UCS-2BE<br /> BOM<br /> 为了说明一个文件采用的是什么编码，在文件最开始的部分，可以有BOM，比如0xFE 0xFF表示UTF-16BE，0xFF 0xFE 0&#215;00  0&#215;00表示UTF-32LE。UTF-8原本是不需要BOM的，因为其自我同步的特性，但是为了明确说明这是UTF-8（而不是让文本编辑器去猜），也 可以加上UTF-8的BOM：0xEF 0xBB 0xBF<br /> 以上内容都讲述得很概略，详细信息请查阅维基百科相关内容。</p> <p>std::locale<br /> 通过前面两节的知识，我们知道了在C/C++中，字符（串）和宽字符（串）之间的转换不是简单的，固定的数学关系，宽窄转换依赖于本地化策略集 （locale）。换句话说，一个程序在运行之前并不知道系统的本地化策略集是什么，程序只有在运行之后才通过locale获得当时的本地化策略集。<br /> C有自己的locale函数，我们这里直接介绍C++的locale类。<br /> 先讨论locale的构造函数：<br /> locale() throw();<br /> 这个构造函数是获得当前程序的locale，用法如下：<br /> std::locale app_loc = std::locale();<br /> 或者（这是构造对象的两种表示方式，后同）<br /> std::locale app_loc;<br /> 另外一个构造函数是：<br /> explicit locale(const char* name);<br /> 这个构造函数以name的名字创建新的locale。重要的locale对象有：<br /> std::locale sys_loc(&#8220;&#8221;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获得当前系统环境的locale<br /> std::locale C_loc(&#8220;C&#8221;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 或者&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::locale C_loc = std::locale::classic();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获得C定义locale<br /> std::locale old_loc = std::locale::global(new_loc);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将new_loc设置为当前全局locale，并将原来的locale返回给old_loc<br /> 除了这些，其它的name具体名字依赖于C++编译器和操作系统，比如Linux下gcc中文系统的locale名字为&#8221;zh_CN.UTF-8&#8243;，中文Windows可以用&#8221;chs&#8221;（更加完整的名字可以用name()函数查看）。<br /> mbstowcs()和wcstombs()<br /> 这两个C运行时库函数依赖于全局locale进行转换，所以，使用前必须先设置全局locale。<br /> std::locale已经包含在&lt;iostream&gt;中了，再加上我们需要用到的C++字符串，所以包含&lt;string&gt;。<br /> 我们先看窄到宽的转换函数：</p> <pre><ol> <li><span>const&nbsp;std::wstring&nbsp;s2ws(const&nbsp;std::string&amp;&nbsp;s)&nbsp; &nbsp;</span></li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;old_loc&nbsp;=&nbsp;std::locale::global(std::locale(""));&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;src_str&nbsp;=&nbsp;s.c_str();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;size_t&nbsp;buffer_size&nbsp;=&nbsp;s.size()&nbsp;+&nbsp;1;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t*&nbsp;dst_wstr&nbsp;=&nbsp;new&nbsp;wchar_t[buffer_size];&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wmemset(dst_wstr,&nbsp;0,&nbsp;buffer_size);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;mbstowcs(dst_wstr,&nbsp;src_str,&nbsp;buffer_size);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::wstring&nbsp;result&nbsp;=&nbsp;dst_wstr;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]dst_wstr;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale::global(old_loc);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;&nbsp; &nbsp;</li> <li>} &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>我们将全局locale设置为系统locale，并保存原来的全局locale在old_loc中。<br /> 在制定转换空间缓存大小的时候，考虑如下：char是用1个或多个对象，也就是1个或者多个字节来表示各种符号：比如，GB2312用1个字节表示数字和 字母，2个字节表示汉字；UTF-8用一个字节表示数字和字母，3个字节表示汉字，4个字节表示一些很少用到的符号，比如音乐中G大调符号等。 wchar_t是用1个对象（2字节或者4字节）来表示各种符号。因此，表示同样的字符串，宽字符串的大小（也就是wchar_t对象的数量）总是小于或 者等于窄字符串大小（char对象数量）的。+1是为了在最后预留一个值为0的对象，以便让C风格的char或者wchar_t字符串自动截断&#8212;&#8212;这当然 是宽串大小等于窄串大小的时候才会用上的，大部分时候，字符串早在前面某个转换完毕的位置就被0值对象所截断了。<br /> 最后我们将全局locale设置回原来的old_loc。<br /> 窄串到宽串的转换函数：</p> <pre><ol> <li><span>const&nbsp;std::string&nbsp;ws2s(const&nbsp;std::wstring&amp;&nbsp;ws)&nbsp; &nbsp;</span></li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;old_loc&nbsp;=&nbsp;std::locale::global(std::locale(""));&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;wchar_t*&nbsp;src_wstr&nbsp;=&nbsp;ws.c_str();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;buffer_size&nbsp;=&nbsp;ws.size()&nbsp;*&nbsp;4&nbsp;+&nbsp;1;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;dst_str&nbsp;=&nbsp;new&nbsp;char[buffer_size];&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;memset(dst_str,&nbsp;0,&nbsp;buffer_size);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wcstombs(dst_str&nbsp;,src_wstr,&nbsp;buffer_size);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;result&nbsp;=&nbsp;dst_str;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]dst_str;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale::global(old_loc);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;&nbsp; &nbsp;</li> <li>} &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>这里考虑转换空间缓存大小的策略正好相反，在最极端的情况下，所有的wchar_t都需要4个char来表示，所以最大的可能就是4倍加1。<br /> 这两个函数在VC和gcc中都能正常运行（MinGW因为前面说到的原因不支持宽字符的正常使用），在VC中会给出不安全的警告，这是告诉给那些弄不清宽窄转换实质的人的警告，对于了解到目前这些知识的你我来说，这就是啰嗦了。</p> <p>locale和facet<br /> C++的locale框架比C更完备。C++除了一个笼统本地策略集locale，还可以为locale指定具体的策略facet，甚至可以用自己定义的 facet去改造一个现有的locale产生一个新的locale。如果有一个facet类NewFacet需要添加到某个old_loc中形成新 new_loc，需要另外一个构造函数，通常的做法是：<br /> std::locale new_loc(old_loc, new NewFacet);<br /> 标准库里的标准facet都具有自己特有的功能，访问一个locale对象中特定的facet需要使用模板函数use_facet：<br /> template &lt;class Facet&gt; const Facet&amp; use_factet(const locale&amp;);<br /> 换一种说法，use_facet把一个facet类实例化成了对象，由此就可以使用这个facet对象的成员函数。<br /> codecvt<br /> codecvt就是一个标准facet。在C++的设计框架里，这是一个通用的代码转换模板&#8212;&#8212;也就是说，并不是仅仅为宽窄转换制定的。<br /> templat &lt;class I, class E, class State&gt; class std::codecvt: public locale, public codecvt_base{&#8230;};<br /> I表示内部编码，E表示外部编码，State是不同转换方式的标识，如果定义如下类型：<br /> typedef std::codecvt&lt;wchar_t, char, mbstate_t&gt; CodecvtFacet;<br /> 那么CodecvtFacet就是一个标准的宽窄转换facet，其中mbstate_t是标准宽窄转换的State。<br /> 内部编码和外部编码<br /> 我们考虑第1节中提到的C++编译器读取源文件时候的情形，当读到L&#8221;中文abc&#8221;的时候，外部编码，也就是源文件的编码，是GB2312或者UTF-8 的char，而编译器必须将其翻译为UCS-2BE或者UTF-32BE的wchar_t，这也就是程序的内部编码。如果不是宽字符串，内外编码都是 char，也就不需要转换了。类似的，当C++读写文件的时候  ，就会可能需要到内外编码转换。事实上，codecvt就正是被文件流缓存basic_filebuf所使用的。理解这一点很重要，原因会在下一小节看 到。<br /> CodecvtFacet的in()和out()<br /> 因为在CodecvtFacet中，内部编码设置为wchar_t，外部编码设置为char，转换模式是标准宽窄转换mbstate_t，所以，类方法 in()就是从char标准转换到wchar_t，out()就是从wchar_t标准转换到char。这就成了我们正需要的内外转换函数。<br /> result in(State&amp; s, const E* from, const E* from_end, const E*&amp; from_next, I* to,&nbsp; I* to_end, I*&amp; to_next) const;<br /> result out(State&amp; s, const I* from, const I* from_end, const I*&amp; from_next, E* to, E* to_end, E*&amp; to_next) const;<br /> 其中，s是非const引用，保存着转换位移状态信息。这里需要重点强调的是，因为转换的实际工作交给了运行时库，也就是说，转换可能不是在程序的主进程 中完成的，而转换工作依赖于查询s的值，因此，如果s在转换结束前析构，就可能抛出运行时异常。所以，最安全的办法是，将s设置为全局变量！<br /> const的3个指针分别是待转换字符串的起点，终点，和出现错误时候的停点（的下一个位置）；另外3个指针是转换目标字符串的起点，终点以及出现错误时候的停点（的下一个位置）。<br /> 代码如下：<br /> 头文件：</p> <pre><ol> <li><span>//Filename&nbsp;string_wstring_cppcvt.hpp&nbsp; &nbsp;</span></li> <li>#ifndef&nbsp;STRING_WSTRING_CPPCVT_HPP&nbsp; &nbsp;</li> <li>#define&nbsp;STRING_WSTRING_CPPCVT_HPP&nbsp; &nbsp;</li> <li>#include&nbsp;&lt;iostream&gt;&nbsp; &nbsp;</li> <li>#include&nbsp;&lt;string&gt;&nbsp; &nbsp;</li> <li>const&nbsp;std::wstring&nbsp;s2ws(const&nbsp;std::string&amp;&nbsp;s);&nbsp; &nbsp;</li> <li>const&nbsp;std::string&nbsp;ws2s(const&nbsp;std::wstring&amp;&nbsp;s);&nbsp; &nbsp;</li> <li>#endif &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>实现：</p> <pre><ol> <li><span>#include&nbsp;"string_wstring_cppcvt.hpp"&nbsp; &nbsp;</span></li> <li>mbstate_t&nbsp;in_cvt_state;&nbsp; &nbsp;</li> <li>mbstate_t&nbsp;out_cvt_state;&nbsp; &nbsp;</li> <li>const&nbsp;std::wstring&nbsp;s2ws(const&nbsp;std::string&amp;&nbsp;s)&nbsp; &nbsp;</li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;sys_loc("");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;src_str&nbsp;=&nbsp;s.c_str();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;size_t&nbsp;BUFFER_SIZE&nbsp;=&nbsp;s.size()&nbsp;+&nbsp;1;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t*&nbsp;intern_buffer&nbsp;=&nbsp;new&nbsp;wchar_t[BUFFER_SIZE];&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wmemset(intern_buffer,&nbsp;0,&nbsp;BUFFER_SIZE);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;extern_from&nbsp;=&nbsp;src_str;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;extern_from_end&nbsp;=&nbsp;extern_from&nbsp;+&nbsp;s.size();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;extern_from_next&nbsp;=&nbsp;0;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t*&nbsp;intern_to&nbsp;=&nbsp;intern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t*&nbsp;intern_to_end&nbsp;=&nbsp;intern_to&nbsp;+&nbsp;BUFFER_SIZE;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t*&nbsp;intern_to_next&nbsp;=&nbsp;0;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;std::codecvt&lt;wchar_t,&nbsp;char,&nbsp;mbstate_t&gt;&nbsp;CodecvtFacet;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;CodecvtFacet::result&nbsp;cvt_rst&nbsp;=&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::use_facet&lt;CodecvtFacet&gt;(sys_loc).in(&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in_cvt_state,&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extern_from,&nbsp;extern_from_end,&nbsp;extern_from_next,&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intern_to,&nbsp;intern_to_end,&nbsp;intern_to_next);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(cvt_rst&nbsp;!=&nbsp;CodecvtFacet::ok)&nbsp;{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(cvt_rst)&nbsp;{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::partial:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"partial";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::error:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"error";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::noconv:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"noconv";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"unknown";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&nbsp;&lt;&lt;&nbsp;",&nbsp;please&nbsp;check&nbsp;in_cvt_state."&nbsp; &nbsp;</li> <li>&lt;&lt;&nbsp;std::endl;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::wstring&nbsp;result&nbsp;=&nbsp;intern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]intern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;&nbsp; &nbsp;</li> <li>}&nbsp; &nbsp;</li> <li>const&nbsp;std::string&nbsp;ws2s(const&nbsp;std::wstring&amp;&nbsp;ws)&nbsp; &nbsp;</li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;sys_loc("");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;wchar_t*&nbsp;src_wstr&nbsp;=&nbsp;ws.c_str();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;size_t&nbsp;MAX_UNICODE_BYTES&nbsp;=&nbsp;4;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;size_t&nbsp;BUFFER_SIZE&nbsp;=&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ws.size()&nbsp;*&nbsp;MAX_UNICODE_BYTES&nbsp;+&nbsp;1;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;extern_buffer&nbsp;=&nbsp;new&nbsp;char[BUFFER_SIZE];&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;memset(extern_buffer,&nbsp;0,&nbsp;BUFFER_SIZE);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;wchar_t*&nbsp;intern_from&nbsp;=&nbsp;src_wstr;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;wchar_t*&nbsp;intern_from_end&nbsp;=&nbsp;intern_from&nbsp;+&nbsp;ws.size();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;wchar_t*&nbsp;intern_from_next&nbsp;=&nbsp;0;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;extern_to&nbsp;=&nbsp;extern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;extern_to_end&nbsp;=&nbsp;extern_to&nbsp;+&nbsp;BUFFER_SIZE;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;extern_to_next&nbsp;=&nbsp;0;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;std::codecvt&amp;lt;wchar_t,&nbsp;char,&nbsp;mbstate_t&gt;&nbsp;CodecvtFacet;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;CodecvtFacet::result&nbsp;cvt_rst&nbsp;=&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::use_facet&lt;CodecvtFacet&gt;(sys_loc).out(&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out_cvt_state,&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intern_from,&nbsp;intern_from_end,&nbsp;intern_from_next,&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extern_to,&nbsp;extern_to_end,&nbsp;extern_to_next);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(cvt_rst&nbsp;!=&nbsp;CodecvtFacet::ok)&nbsp;{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(cvt_rst)&nbsp;{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::partial:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"partial";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::error:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"error";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;CodecvtFacet::noconv:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"noconv";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;"unknown";&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;&lt;&lt;&nbsp;",&nbsp;please&nbsp;check&nbsp;out_cvt_state."&nbsp; &nbsp;</li> <li>&lt;&lt;&nbsp;std::endl;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;result&nbsp;=&nbsp;extern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]extern_buffer;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;&nbsp; &nbsp;</li> <li>} &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>最后补充说明一下std::use_facet&amp;lt;CodecvtFacet&gt;(sys_loc).in()和 std::use_facet&lt;CodecvtFacet&gt;(sys_loc).out()。sys_loc是系统的locale，这个 locale中就包含着特定的codecvt  facet，我们已经typedef为了CodecvtFacet。用use_facet对CodecvtFacet进行了实例化，所以可以使用这个 facet的方法in()和out()。</p> <p>C++的流和本地化策略集<br /> BS在设计C++流的时候希望其具备智能化，并且是可扩展的智能化，也就是说，C++的流可以&#8220;读懂&#8221;一些内容。比如：</p> <p>std::cout &lt;&amp;lt; 123 &amp;lt;&amp;lt; &#8220;ok&#8221; &amp;lt;&amp;lt; std::endl;</p> <p>这句代码中，std::cout是能判断出123是int而&#8221;ok&#8221;是const char[3]。利用流的智能，甚至可以做一些基础类型的转换，比如从int到string，string到int：</p> <pre><ol> <li><span>std::string&nbsp;str("123");&nbsp; &nbsp;</span></li> <li>std::stringstream&nbsp;sstr(str);&nbsp; &nbsp;</li> <li>int&nbsp;i;&nbsp; &nbsp;</li> <li>sstr&nbsp;&gt;&amp;gt;&nbsp;i; &nbsp;</li> <li>&nbsp;</li> <li>int&nbsp;i&nbsp;=&nbsp;123;&nbsp; &nbsp;</li> <li>std::stringstream&nbsp;sstr;&nbsp; &nbsp;</li> <li>sstr&nbsp;&lt;&amp;lt;&nbsp;i;&nbsp; &nbsp;</li> <li>std::string&nbsp;str&nbsp;=&nbsp;sstr.str(); &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>尽管如此，C++并不满足，C++甚至希望流能&#8220;明白&#8221;时间，货币的表示法。而时间和货币的表示方法在世界范围内是不同的，所以，每一个流都有自己 的locale在影响其行为，C++中叫做激活（imbue，也有翻译成浸染）。而我们知道，每一个locale都有多个facet，这些facet并非 总是被use_facet使用的。决定使用哪些facet的，是流的缓存basic_streambuf及其派生类basic_stringbuf和 basic_filebuf。我们要用到的facet是codecvt，这个facet只被basic_filebuf使用&#8212;&#8212;这就是为什么只能用 fstream来实现宽窄转换，而无法使用sstream来实现的原因。<br /> 头文件：</p> <pre><ol> <li><span>//filename&nbsp;string_wstring_fstream.hpp&nbsp; &nbsp;</span></li> <li>#ifndef&nbsp;STRING_WSTRING_FSTREAM_HPP&nbsp; &nbsp;</li> <li>#define&nbsp;STRING_WSTRING_FSTREAM_HPP&nbsp; &nbsp;</li> <li>#include&nbsp;&amp;lt;string&gt;&nbsp; &nbsp;</li> <li>const&nbsp;std::wstring&nbsp;s2ws(const&nbsp;std::string&amp;&nbsp;s);&nbsp; &nbsp;</li> <li>const&nbsp;std::string&nbsp;ws2s(const&nbsp;std::wstring&amp;&nbsp;s);&nbsp; &nbsp;</li> <li>#endif&nbsp;</li> </ol> </pre> <p>实现：</p> <pre><ol> <li><span>#include&nbsp;&lt;string&gt;&nbsp; &nbsp;</span></li> <li>#include&nbsp;&lt;fstream&gt;&nbsp; &nbsp;</li> <li>#include&nbsp;"string_wstring_fstream.hpp"&nbsp; &nbsp;</li> <li>const&nbsp;std::wstring&nbsp;s2ws(const&nbsp;std::string&amp;&nbsp;s)&nbsp; &nbsp;</li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;sys_loc("");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::ofstream&nbsp;ofs("cvt_buf");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;ofs&nbsp;&lt;&amp;lt;&nbsp;s;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;ofs.close();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::wifstream&nbsp;wifs("cvt_buf");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wifs.imbue(sys_loc);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::wstring&nbsp;wstr;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wifs&nbsp;&gt;&amp;gt;&nbsp;wstr;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wifs.close();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;wstr;&nbsp; &nbsp;</li> <li>}&nbsp; &nbsp;</li> <li>const&nbsp;std::string&nbsp;ws2s(const&nbsp;std::wstring&amp;&nbsp;s)&nbsp; &nbsp;</li> <li>{&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::locale&nbsp;sys_loc("");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::wofstream&nbsp;wofs("cvt_buf");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wofs.imbue(sys_loc);&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wofs&nbsp;&lt;&amp;lt;&nbsp;s;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;wofs.close();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::ifstream&nbsp;ifs("cvt_buf");&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;str;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;ifs&nbsp;&gt;&amp;gt;&nbsp;str;&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;ifs.close();&nbsp; &nbsp;</li> <li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str;&nbsp; &nbsp;</li> <li>} &nbsp;</li> <li>&nbsp;</li> </ol> </pre> <p>在窄到宽的转化中，我们先使用默认的本地化策略集（locale）将s通过窄文件流ofs传入文件，这是char到char的传递，没有任何转换； 然后我们打开宽文件流wifs，并用系统的本地化策略集（locale）去激活（imbue）之，流在读回宽串wstr的时候，就是char到 wchar_t的转换，并且因为激活了sys_loc，所以实现标准窄到宽的转换。<br /> 在宽到窄的转化中，我们先打开的是宽文件流wofs，并且用系统的本地化策略集sys_loc激活（imbue）之，这时候，因为要写的文件 cvt_buf是一个外部编码，所以执行了从wchar_t到char的标准转换。读回来的文件流从char到char，不做任何转换。</p> <p>硬编码的硬伤<br /> 我们现在知道，C/C++的宽窄转换是依赖系统的locale的，并且在运行时完成。考虑这样一种情况，我们在简体中文Windows下编译如下语句：<br /> const char* s = &#8220;中文abc&#8221;;<br /> 根据我们之前的讨论，编译器将按照Windows  Codepage936（GB2312）对这个字符串进行编码。如果我们在程序中运行宽窄转换函数，将s转换为宽字符串ws，如果这个程序运行在简体中文 环境下是没问题的，将执行从GB2312到UCS-2BE的转换；但是，如果在其他语言环境下，比如是繁体中文BIG5，程序将根据系统的locale执 行从BIG5到UCS-2BE的转换，这显然就出现了错误。<br /> 补救<br /> 有没有补救这个问题的办法呢？一个解决方案就是执行不依赖locale的宽窄转换。实际上，这就已经不是宽窄转换之间的问题了，而是编码之间转换的问题 了。我们可以用GNU的libiconv实现任意编码间的转换，对于以上的具体情况，指明是从GB2312到UCS-2BE就不会出错。（请参考本人前面 的章节：<a href="../../lf426/archive/2008/03/30/45738.html" target="\&quot;_blank\&quot;">win32下的libiconv</a>），但这显然是一个笨拙的策略：我们在简体中文Windows下必须使用GB2312到UCS-2BE版本的宽窄转换函数；到了BIG5环境下，就必须重新写从BIG5到UCS-2BE的宽窄转换函数。<br /> Windows的策略<br /> Windows的策略是淘汰了窄字符串，干脆只用宽字符串。所有的硬编码全部加上特定宏，比如TEXT()，如果程序是所谓Unicode编译，在编译时就翻译为UCS2-BE&#8212;&#8212;Windows自称为Unicode编程，其本质是使用了UCS-2BE的16位宽字符串。<br /> Linux的策略<br /> Linux下根本就不存在这个问题！因为各种语言的Linux都使用UTF-8的编码，所以，无论系统locale如何变化，窄到宽转换的规则一直是UTF-8到UTF32-BE 。<br /> 跨平台策略<br /> 因为在16位的范围内，UTF32-BE的前16位为0，后16位与UCS2-BE是一样的，所以，即使wchar_t的sizeof()不一样，在一般情况下，跨平台使用宽字符（串）也应该是兼容的。但是依然存在潜在的问题，就是那些4字节的UTF32编码。<br /> gettext策略<br /> 以上都是将ASCII及以外的编码硬编码在程序中的办法。GNU的gettext提供了另外一种选择：在程序中只硬编码ASCII，多语言支持由gettext函数库在运行时加载。（对gettext的介绍请参考本人前面的章节：<a href="../../lf426/archive/2008/03/30/45723.html" target="\&quot;_blank\&quot;">Win32下的GetText</a>）。 gettext的多语言翻译文件不在程序中，而是单独的提出来放在特定的位置。gettext明确的知道这些翻译文件的编码，所以可以准确的告诉给系统翻 译的正确信息，而系统将这些信息以当前的系统locale编码成窄字符串反馈给程序。例如，在简体中文Windows中，gettext的po文件也可以 以UTF-8储存，gettext将po文件翻译成mo文件，确保mo文件在任何系统和语言环境下都能够正确翻译。在运行是传给win32程序的窄串符合 当前locale，是GB2312。gettext让国际化的翻译更加的方便，缺点是目前我没找到支持宽字符串的版本（据说是有ugettext()支持 宽字符串），所以要使用gettext只能使用窄字符串。但是gettext可以转换到宽字符串，而且不会出现宽窄转换的问题，因为gettext是运行 时根据locale翻译的。例如：<br /> const char* s = gettext(&#8220;Chinese a b c&#8221;);<br /> 其中&#8221;Chinese a b c&#8221;在po中的翻译是&#8221;中文abc&#8221;<br /> 使用依赖locale的运行时宽窄转换函数：<br /> const std::wstring wstr = s2ws(s);<br /> 运行时调用该po文件对应的mo文件，在简体中文环境下就以GB2312传给程序，在繁体中文中就以BIG5传给程序，这样s2ws()总能够正常换算编码。<br /> 更多<br /> 在本文的最后，我想回到C++的stream问题上。用fstream转换如此的简单，sstream却不支持。改造一个支持codecvt的 string  stream需要改造basic_stringbuf。basic_stringbuf和basic_filebuf都派生自 basic_streambuf，所不同的是basic_filebuf在构造和open()的时候调用了codecvt，只需要在 basic_stringbuf中添加这个功能就可以了。说起来容易，实际上是需要重新改造一个STL模板，尽管这些模板源代码都是在标准库头文件中现成 的，但是我还是水平有限，没有去深究了。另外一个思路是构建一个基于内存映射的虚拟文件，这个框架在boost的iostreams库中，有兴趣的朋友可 以深入的研究。<br /> （完）</p> 						</div> 					<div> </div> 											<div id="related-posts"> 								<div id="related-posts-social"> 									<h2>Related Posts: </h2> 								</div> 																	 							</div>				</div> 				</div></div></div></div></div><img src ="http://www.cppblog.com/deane/aggbug/153007.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deane/" target="_blank">李阳</a> 2011-08-11 00:08 <a href="http://www.cppblog.com/deane/archive/2011/08/11/153007.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于C++中的临时对象问题</title><link>http://www.cppblog.com/deane/archive/2010/02/25/108428.html</link><dc:creator>李阳</dc:creator><author>李阳</author><pubDate>Thu, 25 Feb 2010 06:44:00 GMT</pubDate><guid>http://www.cppblog.com/deane/archive/2010/02/25/108428.html</guid><wfw:comment>http://www.cppblog.com/deane/comments/108428.html</wfw:comment><comments>http://www.cppblog.com/deane/archive/2010/02/25/108428.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/deane/comments/commentRss/108428.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deane/services/trackbacks/108428.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;C++中真正的临时对象是看不见的，它们不出现在你的源代码中，临时对象的产生在如下几个时刻:&nbsp;1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用构造函数作为隐式类型转换函数时，会创建临时对象。例：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class Integer&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.cppblog.com/deane/archive/2010/02/25/108428.html'>阅读全文</a><img src ="http://www.cppblog.com/deane/aggbug/108428.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deane/" target="_blank">李阳</a> 2010-02-25 14:44 <a href="http://www.cppblog.com/deane/archive/2010/02/25/108428.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>剖析Windows消息处理机制</title><link>http://www.cppblog.com/deane/archive/2010/01/07/105099.html</link><dc:creator>李阳</dc:creator><author>李阳</author><pubDate>Thu, 07 Jan 2010 08:17:00 GMT</pubDate><guid>http://www.cppblog.com/deane/archive/2010/01/07/105099.html</guid><wfw:comment>http://www.cppblog.com/deane/comments/105099.html</wfw:comment><comments>http://www.cppblog.com/deane/archive/2010/01/07/105099.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/deane/comments/commentRss/105099.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deane/services/trackbacks/105099.html</trackback:ping><description><![CDATA[<p><br>前一段，帮人写了个小控件，又温习了一遍Windows消息处理机制，现在把一些知识点总结出来，供大家参考.<br><br><br>1.窗口<br>&nbsp;&nbsp; Windows程序是由一系列的窗口构成的，每个窗口都有自己的窗口过程，窗口过程就是一个拥有有固定 Signature 的 C函数，具体格式如下：</p>
<p>&nbsp;&nbsp; LRESULT CALLBACK WindowProc(HWND hwnd,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT uMsg,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WPARAM wParam,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPARAM lParam<br>&nbsp;&nbsp; );<br>&nbsp;&nbsp; <br>&nbsp;&nbsp; 窗口类型：<br>&nbsp;&nbsp; 可重叠窗口(Overlapped Window)，<br>&nbsp;&nbsp; 弹出窗口(Pop-up Window)，<br>&nbsp;&nbsp; 子窗口(Child Window)<br>&nbsp;&nbsp; <br>&nbsp;&nbsp; 窗口之间的关系: 父子关系，拥有关系，前后关系。<br>&nbsp;&nbsp; <br>2.线程<br>&nbsp;&nbsp;&nbsp; 一个进程至少拥有一个线程，称为主线程，如果一个线程创建了窗口，拥有GUI资源，那么也称该线程为GUI线程,否则就为工作线程。窗口是由线程创建的，<br>&nbsp;创建窗口的线程就拥有该窗口。这种线程拥有关系的概念对窗口有重要的意义：建立窗口的线程必须是为窗口处理所有消息的线程。为了使这个概念更加明<br>&nbsp;确具体，可以想像一个线程建立了一个窗口，然后就结束了。在这种情况下，窗口不会收到一个WM_DESTROY或WM_NCDESTROY消息，因为线程已经结束，不可<br>&nbsp;能被用来使窗口接收和处理这些消息。每个线程，如果它至少建立了一个窗口，都由系统对它分配一个消息队列。这个队列用于窗口消息的派送(dispatch)。<br>&nbsp;为了使窗口接收这些消息，线程必须有它自己的消息循环，消息循环一般如下：<br>&nbsp;<br>&nbsp;MSG msg;<br>&nbsp;while( GetMessage(&amp;msg, NULL, 0, 0) )<br>&nbsp;{<br>&nbsp;&nbsp;TranslateMessage (&amp;msg);<br>&nbsp;&nbsp;DispatchMessage (&amp;msg);<br>&nbsp;}<br>&nbsp;<br>&nbsp;应用程序不断的从消息队列中获取消息,然后系统通过DispatchMessage函数分派消息到相应窗口的窗口过程，使得消息得到处理。当获取到WM_QUIT消息时，<br>&nbsp;GetMessage返回0，循环结束。<br>&nbsp;<br>3.消息<br>&nbsp;消息，就是指Windows发出的一个通知，告诉应用程序某个事情发生了。例如，单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息<br>&nbsp;给应用程序，它被定义为：<br>&nbsp;&nbsp;typedef struct {<br>&nbsp;&nbsp;HWND hwnd;&nbsp;&nbsp;&nbsp;&nbsp;//窗口句柄, 发生在哪个窗口上<br>&nbsp;&nbsp;UINT message;&nbsp;&nbsp;&nbsp;//消息标识号 ( WM_MOUSEMOVE, WM_LBUTTONDOWN, ... )<br>&nbsp;&nbsp;WPARAM wParam;&nbsp;&nbsp;&nbsp;//消息参数1<br>&nbsp;&nbsp;LPARAM lParam;&nbsp;&nbsp;&nbsp;//消息参数2<br>&nbsp;&nbsp;DWORD time;<br>&nbsp;&nbsp;POINT pt;<br>&nbsp;} MSG, *PMSG;<br>&nbsp;一个消息结构体包含了该事件 所有完备信息，当应用程序收到该消息时，就可以做出相应处理了。<br>&nbsp;<br>&nbsp;消息分类</p>
<p>&nbsp;&lt;1&gt;.队列消息和非队列消息 </p>
<p>&nbsp;&nbsp;从消息的发送途径上看，消息分两种：队列消息和非队列消息。<br>&nbsp;&nbsp;队列消息送到系统消息队列，然后到线程消息队列；非队列消息直接送给目的窗口过程。</p>
<p>&nbsp;&nbsp;这里，对消息队列阐述如下：<br>&nbsp;&nbsp;Windows维护一个系统消息队列(System message queue)，每个GUI线程有一个线程消息队列(Thread message queue)。鼠标、键盘事件由鼠标或键盘驱动<br>&nbsp;&nbsp;程序转换成输入消息并把消息放进系统消息队列，例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。Windows每次从系统消息队列移走一个<br>&nbsp;&nbsp;消息，确定它是送给哪个窗口的和这个窗口是由哪个线程创建的，然后，把它放进窗口创建线程的线程消息队列。线程消息队列接收送给该线程所创建窗口<br>&nbsp;&nbsp;的消息。线程从消息队列取出消息，通过Windows把它送给适当的窗口过程来处理。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;除了键盘、鼠标消息以外，队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。这些队列消息以外的绝大多数消息是非队列消息。</p>
<p><br>&nbsp;&lt;2&gt;.系统消息和应用程序消息 </p>
<p>&nbsp;&nbsp;从消息的来源来看，可以分为：系统定义的消息和应用程序定义的消息。</p>
<p>&nbsp;&nbsp;系统消息ID的范围是从0到WM_USER-1，或0X80000到0XBFFFF；应用程序消息从WM_USER(0X0400)到0X7FFF，或0XC000到0XFFFF；WM_USER到0X7FFF范围的消息<br>&nbsp;&nbsp;由应用程序自己使用；0XC000到0XFFFF范围的消息用来和其他应用程序通信，为了ID的唯一性，使用::RegisterWindowMessage来得到该范围的消息ID。<br>&nbsp;<br>&nbsp;&lt;3&gt;.窗口消息，命令消息，控件通知消息<br>&nbsp;&nbsp;根据处理过程的不同,可以分为三类：窗口消息，命令消息，控件通知消息。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;(1).窗口消息<br>&nbsp;&nbsp;&nbsp;一般以WM_开头，如WM_CREATE, WM_SIZE, WM_MOUSEMOVE等标准的Windows消息, 用于窗口相关的事件通知，窗口消息将由系统分配到该窗口的窗口过程处理。<br>&nbsp;&nbsp;(2).命令消息 (WM_COMMAND)<br>&nbsp;&nbsp;&nbsp;一种特殊的窗口消息，它从一个窗口发送到另一个窗口以处理来自用户的请求，通常是从子窗口发送到父窗口，例如，点击按钮时，按钮的父窗口会收到<br>&nbsp;&nbsp;&nbsp;WM_COMMAND消息，用以通知父窗口按钮被点击，经测试：子窗口向父窗口发送WM_COMMAND消息，或者称为父窗口会收到WM_COMMAND消息，操作系统并不是<br>&nbsp;&nbsp;&nbsp;通过将WM_COMMAND消息放入到父窗口的消息队列中去，而是直接调用了父窗口的窗口过程，以 WM_COMMAND 为消息标识参数(UINT uMsg)，实现这个功能的<br>&nbsp;&nbsp;&nbsp;API函数正是:&nbsp;LRESULT DispatchMessage(const MSG *lpmsg);<br>&nbsp;&nbsp;(3).控件通知消息<br>&nbsp;&nbsp;&nbsp;WM_NOTIFY消息，当用户与控件交互(Edit, Button...)时，通知消息会从控件窗口发送到父窗口，这种消息的目的不是为了处理用户命令，而是为了让父窗<br>&nbsp;&nbsp;&nbsp;口能够适时的改变控件。<br>&nbsp;&nbsp;</p>
<p>4.测试<br>&nbsp;&lt;1&gt;.测试代码:<br>&nbsp;<br>&nbsp;&nbsp;消息循环中，将从消息队列中取出的消息逐一打印出来，<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(GetMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg,&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">))<br><img id=Codehighlighter1_38_255_Open_Image onclick="this.style.display='none'; Codehighlighter1_38_255_Open_Text.style.display='none'; Codehighlighter1_38_255_Closed_Image.style.display='inline'; Codehighlighter1_38_255_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_38_255_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_38_255_Closed_Text.style.display='none'; Codehighlighter1_38_255_Open_Image.style.display='inline'; Codehighlighter1_38_255_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_38_255_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_38_255_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;buf[</span><span style="COLOR: #000000">1024</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;sprintf_s(buf,&nbsp;</span><span style="COLOR: #000000">1024</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hWnd:%d&nbsp;uMsg:&nbsp;%d&nbsp;WParam:&nbsp;%d&nbsp;&nbsp;LParam:&nbsp;%d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;msg.hwnd,&nbsp;msg.message,&nbsp;msg.wParam,&nbsp;msg.lParam);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">buf;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;在窗口过程中，如果收到 WM_COMMAND 消息，就在窗口上输入来。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">LRESULT&nbsp;CALLBACK&nbsp;WndProc&nbsp;(HWND&nbsp;hwnd,&nbsp;UINT&nbsp;message,&nbsp;WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)<br><img id=Codehighlighter1_83_621_Open_Image onclick="this.style.display='none'; Codehighlighter1_83_621_Open_Text.style.display='none'; Codehighlighter1_83_621_Closed_Image.style.display='inline'; Codehighlighter1_83_621_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_83_621_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_83_621_Closed_Text.style.display='none'; Codehighlighter1_83_621_Open_Image.style.display='inline'; Codehighlighter1_83_621_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_83_621_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_83_621_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">&nbsp;(message)<br><img id=Codehighlighter1_108_555_Open_Image onclick="this.style.display='none'; Codehighlighter1_108_555_Open_Text.style.display='none'; Codehighlighter1_108_555_Closed_Image.style.display='inline'; Codehighlighter1_108_555_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_108_555_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_108_555_Closed_Text.style.display='none'; Codehighlighter1_108_555_Open_Image.style.display='inline'; Codehighlighter1_108_555_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_108_555_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_108_555_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;WM_COMMAND:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HDhdc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetDC&nbsp;(hwnd)&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SelectObject&nbsp;(hdc,&nbsp;GetStockObject&nbsp;(SYSTEM_FIXED_FONT))&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;TextOut(hdc,&nbsp;</span><span style="COLOR: #000000">24</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;cxChar,&nbsp;cyChar&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;(rect.bottom&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">&nbsp;cyChar&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">),<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szBuffer,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wsprintf(szBuffer,&nbsp;szFormat,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEXT&nbsp;(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">WM_COMMAND</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">),<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HIWORD(wParam),&nbsp;LOWORD(wParam),<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HIWORD(lParam),&nbsp;LOWORD(lParam))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ReleaseDC&nbsp;(hwnd,&nbsp;hdc)&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ValidateRect&nbsp;(hwnd,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">rect)&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;DefWindowProc&nbsp;(hwnd,&nbsp;message,&nbsp;wParam,&nbsp;lParam)&nbsp;;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;2&gt;.运行结果<br>&nbsp;&nbsp;&nbsp;&nbsp;一个窗口，窗口上有一个按钮子窗口，然后还有一个控制台，输出消息循环中的每条消息，当父窗口收到 WM_COMMAND 消息时，<br>&nbsp;&nbsp;&nbsp; 会在屏幕上输出。<br><br><img style="WIDTH: 901px; HEIGHT: 655px" height=655 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/5.jpg" width=901 border=0><br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1). 当鼠标在父窗口上移动时：<br>&nbsp;&nbsp;&nbsp;<br><img height=201 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/1.JPG" width=589 border=0><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可见父窗口 hWnd:&nbsp;461982，uMsg : 521 ( WM_MOUSEMOVE )，从线程消息队列中取出的。<br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(2). 当鼠标在按钮子窗口上移动时：<br><br><img height=224 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/3.jpg" width=589 border=0><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可见按钮 hWnd:&nbsp;462118，uMsg : 521 ( WM_MOUSEMOVE)，从线程消息队列中取出的。<br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(3). 当鼠标在父窗口上点击时：<br><br><img height=163 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/2.JPG" width=559 border=0><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;父窗口收到了&nbsp;513(WM_LBUTTONDOWN), 514(WM_LBUTTONUP) 消息，从线程消息队列中取出的。<br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(4). 当鼠标在按钮窗口上点击时：<br><br><img height=191 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/4.JPG" width=761 border=0><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;按钮窗口从线程的消息队列中取出了 513(WM_LBUTTONDOWN), 514(WM_LBUTTONUP) 消息，父窗口收到了WM_COMMAND<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;消息，TextOut 绘制出 WM_COMMAND 文本。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我在 WM_COMMAND 的消息处理语句处打有断点，看下图:<br><br><img height=464 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/6.jpg" width=554 border=0><br><br>&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hwnd:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00070c9e，十进制就是461982，父窗口句柄；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;273 (WM_COMMAND)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wParam:&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lParam:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;具体是WinMain中的哪一个函数中最后调用了 窗口过程 WndProc 呢，见下图：<br><br><br><br><img height=325 alt="" src="http://www.cppblog.com/images/cppblog_com/deane/messageImg/8.JPG" width=761 border=0><br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;原来是在 DispatchMessage 函数中，再看看参数的值：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msg.hwnd:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00070d26，十进制是462118，是按钮窗口的句柄;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msg.message:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;514 (&nbsp; WM_LBUTTONUP&nbsp; )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;哦~~~~，原来是操作系统在从该线程的消息队列中取出按钮的 WM_LBUTTONUP (鼠标左键释放) 消息后，调用<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage&nbsp;分派消息，DispatchMessage 会先将 WM_LBUTTONUP 消息分派到按钮的窗口过程(系统默认有)，<br>&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;参数， WM_COMMAND 为窗口过程的第二个参数 调用了&nbsp;父窗口的窗口过程，也就是将 WM_COMMAND<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;消息分发到了父窗口，从而使父窗口得到了通知。这些，都是 Windows 来完成的，应用程序只需要在相应的窗口<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;过程中处理相应的消息。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从上面，我们还可以看出，WM_COMMAND 是非队列消息，直接分派到目的窗口过程，而不是放入到消息队列中，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;让消息循环去取。<br><br><br><br>&nbsp;总结:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;简而言之，&nbsp;标准Windows消息发送到产生窗口，通知消息(WM_COMMAND, WM_NOTIFY)发送到父窗口，这是Windows<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;的标准消息处理过程，MFC对 Window API 进行了封装，有自己的一套消息处理流程， 消息顺着一条路径流动，需要<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;处理的对象可以添加消息响应函数处理之，对于命令消息，它有 CView , CDocument,&nbsp; CMainFram ,&nbsp; CWinApp 一系列处理<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 节点，对于通知消息，MFC还加入一种很好的机制：消息反射，就是父窗口收到子窗口发出的通知消息后，会将此消息<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发送给子窗口，先让子窗口处理，如果子窗口不处理，父窗口再处理之，这样有利于将所有消息处理代码都集成了子窗口<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 中，有利于控件的开发。MFC的消息处理，我不予详细讨论了，有兴趣的可以参考侯捷的&lt;&lt;深入浅出MFC&gt;&gt;。<br><br><br><br><br><br><br><br><br><br>
<img src ="http://www.cppblog.com/deane/aggbug/105099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deane/" target="_blank">李阳</a> 2010-01-07 16:17 <a href="http://www.cppblog.com/deane/archive/2010/01/07/105099.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于 return void()</title><link>http://www.cppblog.com/deane/archive/2009/07/08/89536.html</link><dc:creator>李阳</dc:creator><author>李阳</author><pubDate>Wed, 08 Jul 2009 03:54:00 GMT</pubDate><guid>http://www.cppblog.com/deane/archive/2009/07/08/89536.html</guid><wfw:comment>http://www.cppblog.com/deane/comments/89536.html</wfw:comment><comments>http://www.cppblog.com/deane/archive/2009/07/08/89536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/deane/comments/commentRss/89536.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deane/services/trackbacks/89536.html</trackback:ping><description><![CDATA[<br><br>大家都知道，return 用来在函数里返回，有两种形式：一是 直接用return; 或者省略，表示无返回值。二是 return expression; 返回一个值。<br>今天测试时我发现两种以前没注意的方式，也是正确的。<br><br><br>&lt;1&gt;.&nbsp;&nbsp; <br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;FuncA()<br><img id=Codehighlighter1_13_42_Open_Image onclick="this.style.display='none'; Codehighlighter1_13_42_Open_Text.style.display='none'; Codehighlighter1_13_42_Closed_Image.style.display='inline'; Codehighlighter1_13_42_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_13_42_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_13_42_Closed_Text.style.display='none'; Codehighlighter1_13_42_Open_Image.style.display='inline'; Codehighlighter1_13_42_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_13_42_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_13_42_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">();&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">正确的，同：return;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span></div>
<br><br>&lt;2&gt;.<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;FuncB()<br><img id=Codehighlighter1_13_52_Open_Image onclick="this.style.display='none'; Codehighlighter1_13_52_Open_Text.style.display='none'; Codehighlighter1_13_52_Closed_Image.style.display='inline'; Codehighlighter1_13_52_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_13_52_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_13_52_Closed_Text.style.display='none'; Codehighlighter1_13_52_Open_Image.style.display='inline'; Codehighlighter1_13_52_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_13_52_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_13_52_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;FuncA();</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">也可以，同：&nbsp;FuncA();</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span></div>
<br><br><br>这两种特性在某些情况下，是很有用的。比如，我要写一个函数模板，以 任意的模板参数类型 T 为返回值。<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>T&nbsp;FuncC()<br><img id=Codehighlighter1_32_67_Open_Image onclick="this.style.display='none'; Codehighlighter1_32_67_Open_Text.style.display='none'; Codehighlighter1_32_67_Closed_Image.style.display='inline'; Codehighlighter1_32_67_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_32_67_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_32_67_Closed_Text.style.display='none'; Codehighlighter1_32_67_Open_Image.style.display='inline'; Codehighlighter1_32_67_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_32_67_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_32_67_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;T();&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">这里举例返回&nbsp;T();</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>T&nbsp;FuncD()<br><img id=Codehighlighter1_102_127_Open_Image onclick="this.style.display='none'; Codehighlighter1_102_127_Open_Text.style.display='none'; Codehighlighter1_102_127_Closed_Image.style.display='inline'; Codehighlighter1_102_127_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_102_127_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_102_127_Closed_Text.style.display='none'; Codehighlighter1_102_127_Open_Image.style.display='inline'; Codehighlighter1_102_127_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_102_127_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_102_127_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;FuncC</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<br><br>所以即使对于 返回值 为 void 的情况，FuncD&lt;void&gt;(); 也是适用的。<br>如果编译器不支持这种特性。那么当我们就得针对void返回类型进行特化，或者函数重载，示例代码如下：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #008000">//</span><span style="COLOR: #008000">一般处理</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>T&nbsp;FuncE()<br><img id=Codehighlighter1_39_64_Open_Image onclick="this.style.display='none'; Codehighlighter1_39_64_Open_Text.style.display='none'; Codehighlighter1_39_64_Closed_Image.style.display='inline'; Codehighlighter1_39_64_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_39_64_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_39_64_Closed_Text.style.display='none'; Codehighlighter1_39_64_Open_Image.style.display='inline'; Codehighlighter1_39_64_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_39_64_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_39_64_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;FuncC</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">特化版本</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;FuncE</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">()<br><img id=Codehighlighter1_104_125_Open_Image onclick="this.style.display='none'; Codehighlighter1_104_125_Open_Text.style.display='none'; Codehighlighter1_104_125_Closed_Image.style.display='inline'; Codehighlighter1_104_125_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_104_125_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_104_125_Closed_Text.style.display='none'; Codehighlighter1_104_125_Open_Image.style.display='inline'; Codehighlighter1_104_125_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_104_125_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_104_125_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;FuncC</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">或者进行重载亦可</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;FuncE()<br><img id=Codehighlighter1_152_172_Open_Image onclick="this.style.display='none'; Codehighlighter1_152_172_Open_Text.style.display='none'; Codehighlighter1_152_172_Closed_Image.style.display='inline'; Codehighlighter1_152_172_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_152_172_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_152_172_Closed_Text.style.display='none'; Codehighlighter1_152_172_Open_Image.style.display='inline'; Codehighlighter1_152_172_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_152_172_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_152_172_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;FuncC</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Test()<br><img id=Codehighlighter1_188_274_Open_Image onclick="this.style.display='none'; Codehighlighter1_188_274_Open_Text.style.display='none'; Codehighlighter1_188_274_Closed_Image.style.display='inline'; Codehighlighter1_188_274_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_188_274_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_188_274_Closed_Text.style.display='none'; Codehighlighter1_188_274_Open_Image.style.display='inline'; Codehighlighter1_188_274_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_188_274_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_188_274_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;FuncE</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">泛化版本</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;FuncE</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">();&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">特化版本</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;FuncE();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">重载版本</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>FuncE函数没有参数，可以特化或者重载，但如果它还有其他模板参数的话，由于函数模板不支持部分特化，就只能使用重载模板函数了。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br><br>发现这种方式后，为我省了很多事，原来为了识别一个模板参数是否为void，我模拟stl 搞了个 templeate &lt;typename T&gt; Return_Type_Trait {}，然后利用类模板的特化来专门定义一些类型，以到达识别返回类型的目的。现在看来，都是多余的。可以使用这个特性来实现。<br><br><br><br>
<img src ="http://www.cppblog.com/deane/aggbug/89536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deane/" target="_blank">李阳</a> 2009-07-08 11:54 <a href="http://www.cppblog.com/deane/archive/2009/07/08/89536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>