??xml version="1.0" encoding="utf-8" standalone="yes"?>久久综合伊人77777,色婷婷久久综合中文久久蜜桃av,久久电影网http://www.shnenglu.com/lf426/Game Design Using C++ and SDLzh-cnWed, 07 May 2025 19:49:55 GMTWed, 07 May 2025 19:49:55 GMT60LoihQ落? 无敌英雄传说Q?/title><link>http://www.shnenglu.com/lf426/archive/2013/07/22/202025.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 22 Jul 2013 04:17:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2013/07/22/202025.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/202025.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2013/07/22/202025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/202025.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/202025.html</trackback:ping><description><![CDATA[<div>q么长时间了Q我的主要精力放在英语的学习上面。因为我认识到计机U学与国际水q的差距巨大Q而且语言是关键。简单的_你不能指望别人用中文来写注释Q用拼音来写函数?br />对于游戏的设计一直停留在理论Q前D|间研I了下WEQWar3 Map EditorQ,发现q是很强大的Q可以实C部分我的游戏设计理念Q于是作了这么一张对战地图。其主要设计思\是H出兵力分合Q资源控制的{略Q减对手速的要求?br />地图其他信息在这里:<br /><a >http://loih.blog.163.com/</a><br /><br />2013q?0?0日更新Loih Beta 0.11a Team Mode<br />Q团队模式,支持5v5Q?br /><a title="Loih Beta 0.11a Team Mode" href="/Files/lf426/Loih.0.11a.team.rar">Loih Beta 0.11a Team Mode</a><br /><br />2013q??9日更新Loih Beta 0.11a<br />Q包?#8220;标准Ҏ?#8221;?#8220;带野怪版”Q?br /><a title="Loih Beta 0.11a" href="/Files/lf426/Loih.0.11.rar">Loih Beta 0.11a</a><br /><br />落埃生存战(ZLoih 0.07Q带AIQ?br /><a title="落埃生存战下? href="/Files/lf426/Loih.0.07.Survival.rar">落埃生存战下?/a><br /><br />落埃Q无敌英雄传?Beta 0.09e<br /><a title="标准Ҏ?.09e" href="/Files/lf426/Loih.0.09e.rar">标准Ҏ?.09e</a><br /><br />落埃Q无敌英雄传?Beta 0.10b<br /><a title="标准Ҏ?.10b" href="/Files/lf426/Loih.0.10b.rar">标准Ҏ?.10b</a></div><img src ="http://www.shnenglu.com/lf426/aggbug/202025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2013-07-22 12:17 <a href="http://www.shnenglu.com/lf426/archive/2013/07/22/202025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>d解密C++宽字W:6、国际化{略Q完Q?/title><link>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 26 Jun 2010 11:55:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/118788.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/118788.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/118788.html</trackback:ping><description><![CDATA[<a title="<本文pdf文档下蝲>" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲></a><br><br>编码的伤<br><br>我们现在知道QC/C++的宽H{换是依赖pȝ的locale的,q且在运行时完成。考虑q样一U情况,我们在简体中文Windows下编译如下语句:<br>const char* s = "中文abc";<br>Ҏ我们之前的讨论,~译器将按照Windows Codepage936QGB2312Q对q个字符串进行编码。如果我们在E序中运行宽H{换函敎ͼs转换为宽字符串wsQ如果这个程序运行在体中文环境下是没问题的,执行从GB2312到UCS-2BE的{换;但是Q如果在其他语言环境下,比如是繁体中文BIG5Q程序将Ҏpȝ的locale执行从BIG5到UCS-2BE的{换,q显然就出现了错误?br><br>补救<br><br>有没有补救这个问题的办法呢?一个解x案就是执行不依赖locale的宽H{换。实际上Q这已l不是宽H{换之间的问题了,而是~码之间转换的问题了。我们可以用GNU的libiconv实现L~码间的转换Q对于以上的具体情况Q指明是从GB2312到UCS-2BE׃会出错。(请参考本人前面的章节Q?a title=win32下的libiconv href="http://www.shnenglu.com/lf426/archive/2008/03/30/45738.html">win32下的libiconv</a>Q,但这昄是一个笨拙的{略Q我们在体中文Windows下必M用GB2312到UCS-2BE版本的宽H{换函敎ͼCBIG5环境下,必重新写从BIG5到UCS-2BE的宽H{换函数?br><br>Windows的策?br><br>Windows的策略是淘汰了窄字符Ԍq脆只用宽字W串。所有的编码全部加上特定宏Q比如TEXT()Q如果程序是所谓Unicode~译Q在~译时就译为UCS2-BE——Windows自称为Unicode~程Q其本质是用了UCS-2BE?6位宽字符丌Ӏ?br><br>Linux的策?br><br>Linux下根本就不存在这个问题!因ؓ各种语言的Linux都用UTF-8的编码,所以,无论pȝlocale如何变化Q窄到宽转换的规则一直是UTF-8到UTF32-BE ?br><br>跨^台策?br><br>因ؓ?6位的范围内,UTF32-BE的前16位ؓ0Q后16位与UCS2-BE是一LQ所以,即wchar_t的sizeof()不一P在一般情况下Q跨q_使用宽字W(Ԍ也应该是兼容的。但是依然存在潜在的问题Q就是那?字节的UTF32~码?br><br>gettext{略<br><br>以上都是ASCII及以外的~码编码在E序中的办法。GNU的gettext提供了另外一U选择Q在E序中只编码ASCIIQ多语言支持由gettext函数库在q行时加载。(对gettext的介l请参考本人前面的章节Q?a title=Win32下的GetText href="http://www.shnenglu.com/lf426/archive/2008/03/30/45723.html">Win32下的GetText</a>Q。gettext的多语言译文g不在E序中,而是单独的提出来攑֜特定的位|。gettext明确的知道这些翻译文件的~码Q所以可以准的告诉l系l翻译的正确信息Q而系l将q些信息以当前的pȝlocale~码成窄字符串反馈给E序。例如,在简体中文Windows中,gettext的po文g也可以以UTF-8储存Qgettextpo文g译成mo文gQ确保mo文g在Q何系l和语言环境下都能够正确译。在q行是传lwin32E序的窄串符合当前localeQ是GB2312。gettext让国际化的翻译更加的方便Q缺Ҏ目前我没扑ֈ支持宽字W串的版本(据说是有ugettext()支持宽字W串Q,所以要使用gettext只能使用H字W串。但是gettext可以转换到宽字符Ԍ而且不会出现宽窄转换的问题,因ؓgettext是运行时Ҏlocale译的。例如:<br>const char* s = gettext("Chinese a b c");<br>其中"Chinese a b c"在po中的译?中文abc"<br>使用依赖locale的运行时宽窄转换函数Q?br>const std::wstring wstr = s2ws(s);<br>q行时调用该po文g对应的mo文gQ在体中文环境下׃GB2312传给E序Q在J体中文中就以BIG5传给E序Q这样s2ws()总能够正常换编码?br><br>更多<br><br>在本文的最后,我想回到C++的stream问题上。用fstream转换如此的简单,sstream却不支持。改造一个支持codecvt的string stream需要改造basic_stringbuf。basic_stringbuf和basic_filebuf都派生自basic_streambufQ所不同的是basic_filebuf在构造和open()的时候调用了codecvtQ只需要在basic_stringbuf中添加这个功能就可以了。说hҎQ实际上是需要重新改造一个STL模板Q尽这些模板源代码都是在标准库头文件中现成的,但是我还是水qx限,没有LI了。另外一个思\是构Z个基于内存映的虚拟文gQ这个框架在boost的iostreams库中Q有兴趣的朋友可以深入的研究?br>Q完Q? <img src ="http://www.shnenglu.com/lf426/aggbug/118788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-26 19:55 <a href="http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>d解密C++宽字W:5、利用fstream转换http://www.shnenglu.com/lf426/archive/2010/06/26/118779.htmllf426lf426Sat, 26 Jun 2010 08:40:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118779.htmlhttp://www.shnenglu.com/lf426/comments/118779.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118779.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/118779.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118779.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

C++的流和本地化{略?br>
BS在设计C++的时候希望其具备化,q且是可扩展的智能化Q也是_C++的流可以“L”一些内宏V比如:
std::cout << 123 << "ok" << std::endl;
q句代码中,std::cout是能判断?23是int?ok"是const char[3]。利用流的智能,甚至可以做一些基cd的{换,比如从int到stringQstring到intQ?br>
std::string str("123");
std::stringstream sstr(str);
int i;
sstr 
>> i;
int i = 123;
std::stringstream sstr;
sstr 
<< i;
std::
string str = sstr.str();
管如此QC++q不满QC++甚至希望能“明白”旉Q货币的表示法。而时间和货币的表C方法在世界范围内是不同的,所以,每一个流都有自己的locale在媄响其行ؓQC++中叫做激z(imbueQ也有翻译成染Q。而我们知道,每一个locale都有多个facetQ这些facetqL被use_facet使用的。决定用哪些facet的,是流的缓存basic_streambuf及其zcbasic_stringbuf和basic_filebuf。我们要用到的facet是codecvtQ这个facet只被basic_filebuf使用——这是Z么只能用fstream来实现宽H{换,而无法用sstream来实现的原因?br>头文Ӟ
//filename string_wstring_fstream.hpp
#ifndef STRING_WSTRING_FSTREAM_HPP
#define STRING_WSTRING_FSTREAM_HPP

#include 
<string>

const std::wstring s2ws(const std::string& s);
const std::string ws2s(const std::wstring& s);

#endif
实现Q?br>
#include <string>
#include 
<fstream>
#include 
"string_wstring_fstream.hpp"

const std::wstring s2ws(const std::string& s)
{
    std::locale sys_loc(
"");

    std::ofstream ofs(
"cvt_buf");
    ofs 
<< s;
    ofs.close();

    std::wifstream wifs(
"cvt_buf");
    wifs.imbue(sys_loc);
    std::wstring wstr;
    wifs 
>> wstr;
    wifs.close();

    
return wstr;
}

const std::string ws2s(const std::wstring& s)
{
    std::locale sys_loc(
"");

    std::wofstream wofs(
"cvt_buf");
    wofs.imbue(sys_loc);
    wofs 
<< s;
    wofs.close();

    std::ifstream ifs(
"cvt_buf");
    std::
string str;
    ifs 
>> str;
    ifs.close();

    
return str;
}
在窄到宽的{化中Q我们先使用默认的本地化{略集(localeQ将s通过H文件流ofs传入文gQ这是char到char的传递,没有M转换Q然后我们打开宽文件流wifsQƈ用系l的本地化策略集QlocaleQ去Ȁz(imbueQ之Q流在读回宽串wstr的时候,是char到wchar_t的{换,q且因ؓȀzMsys_locQ所以实现标准窄到宽的{换?br>在宽到窄的{化中Q我们先打开的是宽文件流wofsQƈ且用pȝ的本地化{略集sys_locȀz(imbueQ之Q这时候,因ؓ要写的文件cvt_buf是一个外部编码,所以执行了从wchar_t到char的标准{换。读回来的文件流从char到charQ不做Q何{换?

lf426 2010-06-26 16:40 发表评论
]]>
d解密C++宽字W:4、利用codecvt和use_facet转换http://www.shnenglu.com/lf426/archive/2010/06/26/118772.htmllf426lf426Sat, 26 Jun 2010 05:39:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118772.htmlhttp://www.shnenglu.com/lf426/comments/118772.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118772.html#Feedback2http://www.shnenglu.com/lf426/comments/commentRss/118772.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118772.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

locale和facet

C++的locale框架比C更完备。C++除了一个笼l本地策略集localeQ还可以为locale指定具体的策略facetQ甚臛_以用自己定义的facetL造一个现有的locale产生一个新的locale。如果有一个facetcNewFacet需要添加到某个old_loc中Ş成新new_locQ需要另外一个构造函敎ͼ通常的做法是Q?br>std::locale new_loc(old_loc, new NewFacet);
标准库里的标准facet都具有自q有的功能Q访问一个locale对象中特定的facet需要用模板函数use_facetQ?br>template <class Facet> const Facet& use_factet(const locale&);
换一U说法,use_facet把一个facetcd例化成了对象Q由此就可以使用q个facet对象的成员函数?br>
codecvt

codecvt是一个标准facet。在C++的设计框枉Q这是一个通用的代码{换模李쀔—也是_q不是仅仅ؓ宽窄转换制定的?br>templat <class I, class E, class State> class std::codecvt: public locale, public codecvt_base{...};
I表示内部~码QE表示外部~码QState是不同{换方式的标识Q如果定义如下类型:
typedef std::codecvt<wchar_t, char, mbstate_t> CodecvtFacet;
那么CodecvtFacet是一个标准的宽窄转换facetQ其中mbstate_t是标准宽H{换的State?br>
内部~码和外部编?br>
我们考虑W?节中提到的C++~译器读取源文g时候的情ŞQ当dL"中文abc"的时候,外部~码Q也是源文件的~码Q是GB2312或者UTF-8的charQ而编译器必须其译为UCS-2BE或者UTF-32BE的wchar_tQ这也就是程序的内部~码。如果不是宽字符Ԍ内外~码都是charQ也׃需要{换了。类似的Q当C++d文g的时?Q就会可能需要到内外~码转换。事实上Qcodecvt正是被文g缓存basic_filebuf所使用的。理解这一点很重要Q原因会在下一节看到?br>
CodecvtFacet的in()和out()
因ؓ在CodecvtFacet中,内部~码讄为wchar_tQ外部编码设|ؓcharQ{换模式是标准宽窄转换mbstate_tQ所以,cL法in()是从char标准转换到wchar_tQout()是从wchar_t标准转换到char。这成了我们正需要的内外转换函数?br>result in(State& s, const E* from, const E* from_end, const E*& from_next, I* to,  I* to_end, I*& to_next) const;
result out(State& s, const I* from, const I* from_end, const I*& from_next, E* to, E* to_end, E*& to_next) const;
其中Qs是非const引用Q保存着转换位移状态信息。这里需要重点强调的是,因ؓ转换的实际工作交l了q行时库Q也是_转换可能不是在程序的主进E中完成的,而{换工作依赖于查询s的|因此Q如果s在{换结束前析构Q就可能抛出q行时异常。所以,最安全的办法是Q将s讄为全局变量Q?br>const?个指针分别是待{换字W串的v点,l点Q和出现错误时候的停点Q的下一个位|)Q另?个指针是转换目标字符串的LQ终点以及出现错误时候的停点Q的下一个位|)?br>
代码如下Q?br>头文?br>
//Filename string_wstring_cppcvt.hpp

#ifndef STRING_WSTRING_CPPCVT_HPP
#define STRING_WSTRING_CPPCVT_HPP

#include 
<iostream>
#include 
<string>

const std::wstring s2ws(const std::string& s);
const std::string ws2s(const std::wstring& s);

#endif
实现Q?br>
#include "string_wstring_cppcvt.hpp"

mbstate_t in_cvt_state;
mbstate_t out_cvt_state;

const std::wstring s2ws(const std::string& s)
{
    std::locale sys_loc(
"");

    
const char* src_str = s.c_str();
    
const size_t BUFFER_SIZE = s.size() + 1;

    wchar_t
* intern_buffer = new wchar_t[BUFFER_SIZE];
    wmemset(intern_buffer, 
0, BUFFER_SIZE);

    
const char* extern_from = src_str;
    
const char* extern_from_end = extern_from + s.size();
    
const char* extern_from_next = 0;
    wchar_t
* intern_to = intern_buffer;
    wchar_t
* intern_to_end = intern_to + BUFFER_SIZE;
    wchar_t
* intern_to_next = 0;

    typedef std::codecvt
<wchar_t, char, mbstate_t> CodecvtFacet;

    CodecvtFacet::result cvt_rst 
=
        std::use_facet
<CodecvtFacet>(sys_loc).in(
            in_cvt_state,
            extern_from, extern_from_end, extern_from_next,
            intern_to, intern_to_end, intern_to_next);
    
if (cvt_rst != CodecvtFacet::ok) {
        
switch(cvt_rst) {
            
case CodecvtFacet::partial:
                std::cerr 
<< "partial";
                
break;
            
case CodecvtFacet::error:
                std::cerr 
<< "error";
                
break;
            
case CodecvtFacet::noconv:
                std::cerr 
<< "noconv";
                
break;
            
default:
                std::cerr 
<< "unknown";
        }
        std::cerr    
<< ", please check in_cvt_state."
                    
<< std::endl;
    }
    std::wstring result 
= intern_buffer;

    delete []intern_buffer;

    
return result;
}

const std::string ws2s(const std::wstring& ws)
{
    std::locale sys_loc(
"");

    
const wchar_t* src_wstr = ws.c_str();
    
const size_t MAX_UNICODE_BYTES = 4;
    
const size_t BUFFER_SIZE =
                ws.size() 
* MAX_UNICODE_BYTES + 1;

    
char* extern_buffer = new char[BUFFER_SIZE];
    memset(extern_buffer, 
0, BUFFER_SIZE);

    
const wchar_t* intern_from = src_wstr;
    
const wchar_t* intern_from_end = intern_from + ws.size();
    
const wchar_t* intern_from_next = 0;
    
char* extern_to = extern_buffer;
    
char* extern_to_end = extern_to + BUFFER_SIZE;
    
char* extern_to_next = 0;

    typedef std::codecvt
<wchar_t, char, mbstate_t> CodecvtFacet;

    CodecvtFacet::result cvt_rst 
=
        std::use_facet
<CodecvtFacet>(sys_loc).out(
            out_cvt_state,
            intern_from, intern_from_end, intern_from_next,
            extern_to, extern_to_end, extern_to_next);
    
if (cvt_rst != CodecvtFacet::ok) {
        
switch(cvt_rst) {
            
case CodecvtFacet::partial:
                std::cerr 
<< "partial";
                
break;
            
case CodecvtFacet::error:
                std::cerr 
<< "error";
                
break;
            
case CodecvtFacet::noconv:
                std::cerr 
<< "noconv";
                
break;
            
default:
                std::cerr 
<< "unknown";
        }
        std::cerr    
<< ", please check out_cvt_state."
                    
<< std::endl;
    }
    std::
string result = extern_buffer;

    delete []extern_buffer;

    
return result;
}
最后补充说明一下std::use_facet<CodecvtFacet>(sys_loc).in()和std::use_facet<CodecvtFacet>(sys_loc).out()。sys_loc是系l的localeQ这个locale中就包含着特定的codecvt facetQ我们已ltypedefZCodecvtFacet。用use_facet对CodecvtFacetq行了实例化Q所以可以用这个facet的方法in()和out()?

lf426 2010-06-26 13:39 发表评论
]]>
d解密C++宽字W:3、利用Cq行时库函数转换http://www.shnenglu.com/lf426/archive/2010/06/26/118762.htmllf426lf426Sat, 26 Jun 2010 03:17:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118762.htmlhttp://www.shnenglu.com/lf426/comments/118762.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118762.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/118762.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118762.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

std::locale

通过前面两节的知识,我们知道了在C/C++中,字符Q串Q和宽字W(Ԍ之间的{换不是简单的Q固定的数学关系Q宽H{换依赖于本地化策略集QlocaleQ。换句话_一个程序在q行之前q不知道pȝ的本地化{略集是什么,E序只有在运行之后才通过locale获得当时的本地化{略集?br>C有自qlocale函数Q我们这里直接介lC++的localecR?br>先讨论locale的构造函敎ͼ
locale() throw();
q个构造函数是获得当前E序的localeQ用法如下:
std::locale app_loc = std::locale();
或者(q是构造对象的两种表示方式Q后同)
std::locale app_loc;
另外一个构造函数是Q?br>explicit locale(const char* name);
q个构造函Cname的名字创建新的locale。重要的locale对象有:
std::locale sys_loc("");      //获得当前pȝ环境的locale
std::locale C_loc("C");      或?nbsp;     std::locale C_loc = std::locale::classic();      //获得C定义locale
std::locale old_loc = std::locale::global(new_loc);      //new_loc讄为当前全局localeQƈ原来的localeq回lold_loc
除了q些Q其它的name具体名字依赖于C++~译器和操作pȝQ比如Linux下gcc中文pȝ的locale名字?zh_CN.UTF-8"Q中文Windows可以?chs"Q更加完整的名字可以用name()函数查看Q?br>
mbstowcs()和wcstombs()

q两个Cq行时库函数依赖于全局localeq行转换Q所以,使用前必d讄全局locale?br>std::locale已经包含?lt;iostream>中了Q再加上我们需要用到的C++字符Ԍ所以包?lt;string>?br>我们先看H到宽的转换函数Q?br>
const std::wstring s2ws(const std::string& s)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const char* src_str = s.c_str();
    
const size_t buffer_size = s.size() + 1;
    wchar_t
* dst_wstr = new wchar_t[buffer_size];
    wmemset(dst_wstr, 
0, buffer_size);
    mbstowcs(dst_wstr, src_str, buffer_size);
    std::wstring result 
= dst_wstr;
    delete []dst_wstr;

    std::locale::global(old_loc);

    
return result;
}
我们全局locale讄为系llocaleQƈ保存原来的全局locale在old_loc中?br>在制定{换空间缓存大的时候,考虑如下Qchar是用1个或多个对象Q也是1个或者多个字节来表示各种W号Q比如,GB2312?个字节表C数字和字母Q?个字节表C汉字;UTF-8用一个字节表C数字和字母Q?个字节表C汉字,4个字节表CZ些很用到的W号Q比如音乐中G大调W号{。wchar_t是用1个对象(2字节或?字节Q来表示各种W号。因此,表示同样的字W串Q宽字符串的大小Q也是wchar_t对象的数量)L于或者等于窄字符串大(char对象数量Q的?1是ؓ了在最后预留一个gؓ0的对象,以便让C风格的char或者wchar_t字符串自动截断——这当然是宽串大等于窄串大的时候才会用上的Q大部分时候,字符串早在前面某个{换完毕的位置p0值对象所截断了?br>最后我们将全局locale讄回原来的old_loc?br>H串到宽串的转换函数Q?br>
const std::string ws2s(const std::wstring& ws)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const wchar_t* src_wstr = ws.c_str();
    size_t buffer_size 
= ws.size() * 4 + 1;
    
char* dst_str = new char[buffer_size];
    memset(dst_str, 
0, buffer_size);
    wcstombs(dst_str ,src_wstr, buffer_size);
    std::
string result = dst_str;
    delete []dst_str;

    std::locale::global(old_loc);

    
return result;
}
q里考虑转换I间~存大小的策略正好相反,在最极端的情况下Q所有的wchar_t都需?个char来表C,所以最大的可能是4倍加1?br>q两个函数在VC和gcc中都能正常运行(MinGW因ؓ前面说到的原因不支持宽字W的正常使用Q,在VC中会l出不安全的警告Q这是告诉给那些弄不清宽H{换实质的人的警告Q对于了解到目前q些知识的你我来_q就是啰嗦了?

lf426 2010-06-26 11:17 发表评论
]]>
d解密C++宽字W:2、Unicode和UTFhttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.htmllf426lf426Fri, 25 Jun 2010 13:51:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.htmlhttp://www.shnenglu.com/lf426/comments/118739.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/118739.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118739.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

Unicode和UCS

Unicode和UCS是两个独立的l织分别制定的一套编码标准,但是因ؓ历史的原因,q两套标准是完全一L。Unicodeq个词用得比较多的原因可能是因ؓ比较ҎCQ如果没有特别的声明Q在本文所提及的Unicode和UCS是一个意思。Unicode的目标是建立一套可以包含hcL有语a文字W号你想得到想不到的各种东西的编码,其编码容量甚至预留了火星语以及银河系以外语言的空间——开个玩W,反正单的_Unicode~码集够的大,如果用计机单位来表C,其数量比3个字节大一些,不到4个字节?br>
Unicode和UTF

因ؓUnicode包含的内容太多,其编码在计算Z的表C方法就成ؓ了一个有必要研究的问题。传l编码,比如标准?位ASCIIQ在计算Z的表C方法就是占一个字节的?位,q似乎是不需要解释就W合大家习惯的表C方法。但是当今Unicode的L辑ֈ32位(计算机的最单位是字节Q所以大?字节Q就只能臛_?字节表示Q,对于大部分常用字W,比如Unicode~码只占一个字节大的p字母Q占两个字节大小汉字Q都?个字节来储存太奢侈了。另外,如果都用4字节直接表示Q就不可避免的出Cؓ0的字节。而我们知道,在C语言中,0x00的字节就?\0'Q表C的是一个字W串Qchar字符Ԍ非wchar_tQ的l束Q换句话_C风格的char字符串无法表CUnicode?br>因ؓcM的种U问题,为Unicode在计机中的~码Ҏ出现了,q就是UTFQ所对应的,为UCS~码实现的方式也有自q说法。一般来_UTF-xQx表示q套~码一个单位至占用x位,因ؓUnicode最长达?2位,所以UTF-x通常是变长的——除了UTF-32Q而UCS-y表示一个单位就占用y个字节,所以能表示当今Unicode的UCS-y只有UCS-4Q但是因为历史的原因Q当Unicodeq没那么庞大的时候,2个字节够表C,所以有UCS-2Q现在看来,UCS-2所能表C的Unicode只是当今Unicode的一个子集?br>也就是说Q如果某U编码,能根据一定的规则法Q得到Unicode~码Q那么这U编码方式就可以UC为UTF?br>
UTF-8和Windows GB2312

UTF-8是一?#8220;聪明”的编码,可能?Q?Q?Q?个字节表C。通过UTF-8的算法,每一个字节表C的信息都很明确Q这是不是某个Unicode~码的第一个字节;如果是第一个字节,q是一个几位Unicode~码。这U?#8220;聪明”被称为UTF-8的自我同步,也是UTF-8成ؓ|络传输标准~码的原因?br>另外QUTF-8也不会出?字节Q所以可以表CZؓchar字符Ԍ所以可以成为系l的~码。Linuxpȝ默认使用UTF-8~码?br>Windows GB2312一般自UCؓGB2312Q其实真正的名字应该是Windows Codepage 936Q这也是一U变长的~码Q?个字节表CZl的ASCII部分Q汉字部分是两个字节的GBKQ国标扩Q展Q,拼音声母Q。Codepage 936也可以表CZؓchar字符Ԍ是中文Windowspȝ的默认编码?br>我们在第1节中看到?br>const char* s = "中文abc";
在Windows中的~码是Codepage 936Q在Linux中的~码是UTF-8?br>需要注意的是,Codepage 936不像UTFQ跟Unicode没有换算的关p,所以只能通过“代码?#8221;技术查表对应?br>
UTF-16和UCS-2

UTF-16?个字节或?个字节表C。在2个字节大的时候,跟UCS-2是一L。UTF-16不像UTF-8Q没有自我同步机Ӟ所以,~码大位在前q是位在前Q就成了见仁见智的问题。我们在W?节中Q?#8220;?#8221;的UCS-2BEQ因为是两个字节Q所以也是UTF-16BEQ编码是0x4E2DQ这里的BE是大位在后的意思(也就是小位在前了Q,对应的,如果是UCS-2LEQ编码就成了0x2D4E?br>Windows中的wchar_t是采用UCS-2BE~码。需要指出的是,C++标准中对wchar_t的要求是要能表示所有系l能识别的字W。Windows自称支持UnicodeQ但是其wchar_t却不能表C所有的UnicodeQ由此违背了C++标准?br>
UTF-32和UCS-4

UTF-32在目前阶D늭价于UCS-4Q都用定长的4个字节表C。UTF-32同样存在BE和LE的问题。Linux的wchar_t~码是UTF-32BE。在16位以内的时候,UTF-32BE的后两位Q前两位?x00 0x00Q等价于UTF-16BE也就{h于UCS-2BE

BOM

Z说明一个文仉用的是什么编码,在文件最开始的部分Q可以有BOMQ比?xFE 0xFF表示UTF-16BEQ?xFF 0xFE 0x00 0x00表示UTF-32LE。UTF-8原本是不需要BOM的,因ؓ其自我同步的Ҏ,但是Z明确说明q是UTF-8Q而不是让文本~辑器去猜)Q也可以加上UTF-8的BOMQ?xEF 0xBB 0xBF

以上内容都讲q得很概略,详细信息h阅维基百U相兛_宏V?

lf426 2010-06-25 21:51 发表评论
]]>
d解密C++宽字W:1、从char到wchar_thttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.htmllf426lf426Fri, 25 Jun 2010 06:41:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.htmlhttp://www.shnenglu.com/lf426/comments/118707.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.html#Feedback6http://www.shnenglu.com/lf426/comments/commentRss/118707.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118707.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

“q个问题比你惌中复?#8221;
Q我也学下BS的风|虽然q句话是我自׃时想说的。^^Q?br>
从字W到整数

char是一U整数类型,q句话的含义是,char所能表C的字符在C/C++中都是整数类型。好Q接下来Q很多文章就会DZ个典型例子,比如Q?a'的数值就?x61。这U说法对吗?如果你细心的读过K&R和BS对于C和C++描述的原著,你就会马上反驳道Q?x61只是'a'的ASCII|q没有Q何规定C/C++的char值必d应ASCII。C/C++甚至没有规定char占几位,只是规定了sizeof(char){于1?br>当然Q目前大部分情况下,char?位的Qƈ且,在ASCII范围内的|与ASCII对应?br>
本地化策略集QlocaleQ?br>
“?a'译?x61的整数?#8221;Q?#8220;ASCII范围内的~码与char的整数值对应v?#8221;Q类DL规定Q是特定pȝ和特定编译器制定的,C/C++中有个特定的名词来描q这U规定的集合Q本地化{略集(locale。也有翻译成“现场”Q。而翻译——也是代码转换QcodecvtQ只是这个集合中的一个,C++中定义ؓ{略Qfacet。也有翻译ؓ“刻面”Q?br>
C/C++的编译策?br>
“本地化策略集”是个很好的概念,可惜在字W和字符串这个层面上QC/C++q不使用QC++的locale通常只是影响(streamQ)QC/C++使用更直接简单的{略Q硬~码?br>单的_字符Q串Q在E序文gQ可执行文gQ非源文Ӟ中的表示Q与在程序执行中在内存中的表CZ致。考虑两种情况Q?br>A、char c = 0x61;
B、char c = 'a';
情况A下,~译器可以直接认识作为整数的cQ但是在情况B下,~译器必d'a'译成整数。编译器的策略也很简单,是直接d字符Q串Q在源文件中的编码数倹{比如:
const char* s = "中文abc";
q段字符串在GB2312QWindows 936Q,也就是我们的windows默认中文pȝ源文件中的编码ؓQ?br>0xD6   0xD0   0xCE 0xC4 0x61 0x62 0x63
在UTF-8Q也是Linux默认pȝ源文件中的编码ؓQ?br>0xE4   0xB8   0xAD   0xE6   0x96   0x87   0x61   0x62   0x63
一般情况下Q编译器会忠实于源文件的~码为s赋|例外的情冉|如VC会自作聪明的把大部分其他cd~码的字W串转换成GB2312Q除了像UTF-8 without signatureq样的幸存者)?br>E序在执行的时候,s也就保持是这L~码Q不会再做其他的转换?br>
宽字W?wchar_t
正如char没有规定大小Qwchar_t同样没有标准限定Q标准只是要求一个wchar_t可以表示Mpȝ所能认识的字符Q在win32中,wchar_t?6位;Linux中是32位。wchar_t同样没有规定~码Q因为Unicode的概忉|们后面才解释Q所以这里只是提一下,在win32中,wchar_t的编码是UCS-2BEQ而Linux中是UTF-32BEQ等价于UCS-4BEQ,不过单的_?6位以内,一个字W的q?U编码值是一L。因此:
const wchar_t* ws = L"中文abc";
的编码分别ؓQ?br>0x4E2D   0x6587    0x0061   0x0062   0x0063                                                //win32Q?6?br>0x00004E2D   0x00006587    0x00000061   0x00000062   0x00000063        //LinuxQ?2?br>大写的L是告诉编译器Q这是宽字符丌Ӏ所以,q时候是需要编译器Ҏlocale来进行翻译的?br>比如Q在Windows环境中,~译器的译{略是GB2312到UCS-2BEQLinux环境中的{略是UTF-8到UTF-32BE?br>q时候就要求源文件的~码与编译器的本地化{略集中代码译的策略一_例如VC只能dGB2312的源代码Q这里还是例外,VC太自作聪明了 Q会很多其他代码在~译时自动{换成GB2312Q,而gcc只能dUTF-8的源代码Q这里就有个尬QMinGWq行win32下,所以只有GB2312pȝ才认Q而MinGW却用gcc~写Q所以自己只认UTF-8Q所以结果就是,MinGW的宽字符被废掉了Q?br>宽字W(Ԍq译器译Q还是被编码进E序文g中?

lf426 2010-06-25 14:41 发表评论
]]>
socket ~程入门教程Q六QUDP应用Q?、UDP版的Echo Clienthttp://www.shnenglu.com/lf426/archive/2010/06/12/117690.htmllf426lf426Sat, 12 Jun 2010 04:11:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/12/117690.htmlhttp://www.shnenglu.com/lf426/comments/117690.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/12/117690.html#Feedback2http://www.shnenglu.com/lf426/comments/commentRss/117690.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117690.html同样的,我们UDP版的doEcho()也设计成q回boolQtrue表示循环l箋Qfalse表示关闭客户端?/p>
class UDPEchoClient: public UDPClientSock{
public:
    
explicit UDPEchoClient(
                
int pre_buffer_size = 32);
    
~UDPEchoClient();
    
bool doEcho(const std::string& echo_message);
};
我们依然使用C++字符丌Ӏ?br>
UDPEchoClient::UDPEchoClient(
                
int pre_buffer_size):
UDPClientSock(pre_buffer_size)
{}

UDPEchoClient::
~UDPEchoClient()
{}

bool UDPEchoClient::doEcho(const std::string& echo_message)
{
    
if ( UDPSendtoDest(echo_message.data(), echo_message.size()) < 0) {
        
return false;
    }
    
if (echo_message == "/shutdown") {
        
return false;
    }
    
if (UDPReceive() < 0) {
        
return false;
    }
    std::cout.write(preBuffer, preReceivedLength);
    std::cout 
<< std::endl;
    
return true;
}
当echo_message?#8220;I?#8221;的时候,卌入直接回车,是一?"Q用C风格来说Q即?\0'Q从C++来说Q是const char[1]Q其C++风格的长度echo_message.size()?Q这时候就会发送一?#8220;0长度”的UDP数据包?br>另外Q我们小心设计了关闭服务器的hQ发?shutdown后,客户端会自动q回falseQ表CZ关闭Q不再等待来自服务器的recvfrom()。否则,服务器已l关闭,recvfrom()则会一直阻塞?br>
int main(int argc, char* argv[])
{
    unsigned 
short server_port = 5000;
    
if (argc == 3 && atoi(argv[2]) > 0) {
        server_port 
= atoi(argv[2]);
    }

    WinsockAPI winsockInfo;
    winsockInfo.showVersion();

    UDPEchoClient echo_client;
    echo_client.UDPSetDest(argv[
1], server_port);

    std::
string msg;
    
bool go_on = true;
    
while (msg != "/exit" && go_on){
        std::cout 
<< "Echo: ";
        std::getline(std::cin, msg);
        go_on 
= echo_client.doEcho(msg);
    }

    
return 0;
}
ȝ序中Q如果?exitQ会先发送给服务器,然后再关闭?br>本章完整源代码:
LinuxQ?br>http://www.163pan.com/files/c0l000h0t.html
win32Q?br>http://www.163pan.com/files/c0o000h09.html

lf426 2010-06-12 12:11 发表评论
]]>
socket ~程入门教程Q六QUDP应用Q?、UDP版的Echo Serverhttp://www.shnenglu.com/lf426/archive/2010/06/12/117689.htmllf426lf426Sat, 12 Jun 2010 03:16:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/12/117689.htmlhttp://www.shnenglu.com/lf426/comments/117689.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/12/117689.html#Feedback2http://www.shnenglu.com/lf426/comments/commentRss/117689.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117689.html
class UDPEchoServer: public UDPServerSock{
public:
    
explicit UDPEchoServer(
                unsigned 
short server_port,
                
int pre_buffer_size = 32);
    
~UDPEchoServer();
    
bool handEcho();
};
我们依然让handEcho()q回一个boolQtrue表示客户?#8220;正常”dQ这里没?#8220;断开”q个词是因ؓUDP是无q接的;另外Q我们这里用recvfrom()q回于0来表C客L其实?#8220;非正?#8221;的离开了,比如q接被重|。事实上Q作为UDP服务器,Ҏ不关心客L是在q还是已l离开Q,false表示客户端发出指令要求服务器端关闭?br>
UDPEchoServer::UDPEchoServer(
                unsigned 
short server_port,
                
int pre_buffer_size):
UDPServerSock(server_port, pre_buffer_size)
{}

UDPEchoServer::
~UDPEchoServer()
{}

bool UDPEchoServer::handEcho()
{
    
const std::string SHUTDOWN_CMD = "/shutdown";
    
while (UDPReceive() >= 0) {
        std::
string cmd(preBuffer, SHUTDOWN_CMD.size());
        
if (cmd == SHUTDOWN_CMD &&
            
preReceivedLength == static_cast<int>(SHUTDOWN_CMD.size())) {
            
return false;
        }
        std::cout    
<< "Client ( "
                    
<< inet_ntoa(lastfromSockAddr.sin_addr)
                    
<< " : "
                    
<< ntohs(lastfromSockAddr.sin_port)
                    
<< " ) sent a message."
                    
<< std::endl;
        UDPSetDest(lastfromSockAddr);
        UDPSendtoDest(preBuffer, preReceivedLength);
    }
    
return true;
}
q里跟TCP有些l微的差别。在TCP中,recv()q回0表示q接正常断开Q而UDP中没有连接和断开的概念,recv()或者recvfrom()q回0表示收到一?字节大小数据的数据报。另外,因ؓTCP是一对一q接的,所以一旦连接上QTCP服务器只能处理来自一个客L的echohQ后面会讲到多线E的使用Q就可以让TCP同时处理多个客户端了Q;而UDP服务器则可以处理来自M客户端的echohQؓ了返回信息到正确的客LQ我们的{略是,接收一个UDP数据包后Q马上刷新发送目标地址Z一ơ接收地址Q然后再回发数据Q所以这里每ơ多了一个重新指定发送目的地的函数?br>最后,ȝ序基本不需要改变:
int main(int argc, char* argv[])
{
    
const unsigned short DEFAULT_PORT = 5000;
    unsigned 
short server_port = DEFAULT_PORT;
    
if (argc == 2 && atoi(argv[1]) > 0) {
        server_port 
= atoi(argv[1]);
    }

    UDPEchoServer echo_server(server_port);

    
bool go_on = true;
    
while (go_on){
        go_on 
= echo_server.handEcho();
    }

    
return 0;
}
本章完整源代码下载:
LinuxQ?br>http://www.163pan.com/files/c0l000h0s.html
win32Q?br>http://www.163pan.com/files/c0o000h08.html

lf426 2010-06-12 11:16 发表评论
]]>
socket ~程入门教程Q五QUDP原理Q?、预读MSG_PEEKhttp://www.shnenglu.com/lf426/archive/2010/06/11/117631.htmllf426lf426Fri, 11 Jun 2010 05:30:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/11/117631.htmlhttp://www.shnenglu.com/lf426/comments/117631.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/11/117631.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/117631.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117631.html
#include <sys/types.h>
#include 
<sys/socket.h>
ssize_t recv(
int s, void *buf, size_t len, int flags);
ssize_t recvfrom(
int s, void *buf, size_t len, int flags,
                              struct sockaddr *from, socklen_t *fromlen);
因ؓUDP是按数据包接收的Q我们在接收之前q不知道q个数据包有多大。一个策略是Q我们准备够大的应用程序缓存以免出错,但是q个“_?#8221;的概忉|建立在我们对传送的数据事先有了解的情况下,比如是我们自p计服务器端和客户端ƈ且制定应用层协议Q另外一U策略是Q将一个数据包的相关信息记录在数据包的前面的一些字节中Q比如说大小Q这P我们可以通过预读数据包的前面一D,得到q个数据包的相关信息Q比如说大小Q然后再安排~存?br>q个预读的flag是MSG_PEEK。用预dQRecvQ的下一条UDP数据包信息被d来,但是q不从RecvQ中弹出?br>UDP也可以通过recvfrom()预读获得来向的远E地址Q从而可以提供给比如connect(){函C用?br>需要说明的是,在Linux下(我是DebianpȝQ从一个n字节的UDP数据包中预读取小于n个字节的数据是完全没有问题的Q但是在WinSock下会引v一个异?0040QWSAEMSGSIZEQ,x说win32下recv()或者recvfrom()在这U情况下会返?1。其异常信息大概是读取的数据长度于数据包的长度——而这个正是我们计划中的事情?

lf426 2010-06-11 13:30 发表评论
]]>
޹þþþƷС˵| þ99ù龫Ʒ66| þAVӰ| Ůͬþ| þ̳| þùƷһ| ݺݾƷþþĻ| ŷ龫Ʒþþþ| ɫۺϾþ| þ99һ | 㽶þһ޶ӰԺ| þҹɫƷ鶹| Ů޾Ʒþþۺ| ޾ƷþëƬ| ھƷþþþӰԺ| þþþþþþòҰ߳| ɫۺϾþ | ¾þþþa| 91ƷɫۺϾþ| ɫۺϾþ۾Ʒ| Ʒ޾þþþþ| þþþþϸ| vaþþþ| þùȾƷҰAV| 鶹Ʒþһ| 99þùѸ| þ޾Ʒһ | ݺɫۺþö| ɫۺϾþ88ɫۺ| ҹƷþþþþ| ޾Ʒþþþȥq| þۺϸϾþù| ŮһaëƬþw | aaþ| þþƷһ| 99Ʒ99þþþþ97 | þۺ97ɫһһ| þþƷ69Ʒ| ŷ˾þۺ| 鶹AV뾫Ʒþ| ۺϾþþ|