当前位置: 首页 > news >正文

宁波企业网站排名优化wordpress文本地化

宁波企业网站排名优化,wordpress文本地化,哪个做问卷网站佣金高,济南个人急售二手房《C字符串完全指南--第一部分:win32 字符编码》 原作者:Michael Dun 译 者:Dingqiao Wang 引言 毫无疑问#xff0c;你肯定见过像TCHAR, std::string, BSTR等等这类字符串类型.也包括一些以_tcs开头的奇怪的宏。也许你正盯着屏幕哇哇的发愁#xff0c;然… 《C字符串完全指南--第一部分:win32 字符编码》     原作者:Michael Dun       译    者:Dingqiao Wang   引言 毫无疑问你肯定见过像TCHAR, std::string, BSTR等等这类字符串类型.也包括一些以_tcs开头的奇怪的宏。也许你正盯着屏幕哇哇的发愁然而阅读完本文情况将会改观。这篇指南概述了引入各种类型字符串的目的展示了它们的一些简单用法同时描述了在必要的时候在它们之间如何进行转换。 在第一部分将会涉及三种类型的字符编码。理解编码方案的工作原理对你至关重要。即使你现在已经知道字符串是一个字符数组还是看看这部分内容。一旦你阅读了这些内容你就清楚了这么多字符串类之间的联系。 在第二部分将描述字符串类本身包括什么时候使用哪种类以及如何在他们之间进行转换。 基本字符-----ASCIIDBCSUnicode 所有的字符串类最终都归结为C风格的字符串而C风格的字符串就是字符数组因此我首先介绍下字符类型。有三种编码方案和三种字符类型。第一种方案是单字节编码(single-byte character set, or SBCS).这种方案里所有字符都正好是一个字节长。ASCII码就是单字节编码的例子。单字节字符串以一个字节的0做结束标志。 第二种编码方案是多字节编码(multi-byte character set, or MBCS).在多字节编码中包含一些单字节长的字符也包含其它的多余一个字节长度的字符。在Windows中使用的多字节编码方案中包含两种类型单字节和双字节类型。由于在Windows中使用到的最长的多字节字符也就是2个字节长因此常常用双字节字符集(double-byte character set, or DBCS)来代替MBCS. 在双字节编码方式中一些值被保留来指示他们是双字节的一部分。举个例子在Shift-JIS编码(一种常用的日文编码方案)中介于0x81-0x9F and 0xE0-0xFC之间的值就用来说明这是双字节字符它的下一个字节是其一部分。这些值被称作头部字节(lead bytes)他们总是比0X7F大。紧跟在头部字节后的下一字节被称作后随字节(trail bytes)。在双字节编码中后随字节可以为任意非零值。和单字节编码一样双字节编码使用单字节的0值作为结束符。 第三种方案是Unicode。Unicode 是一种所有字符均采用二个字节的编码标准。Unicode字符有时也被称作宽字节(wide characters)因为他们比单字节占用更多存贮。注意Unicode并不是一种多字节编码——多字节编码的显著特点是字符是不同长度的。一个Unicode字符串以两个0值字节作为结束标志(0值的宽字符形式)。 单字节字符包括拉丁文字母带重音的字符(accented characters),ASCII标准和DOS系统中定义的图形符号。双字节字符在东亚和中东地区的语言中使用。Unicode在COM和Windows NT 内部使用。 你肯定已经很熟悉单字节字符了。当你在使用char类型时,处理的就是单字节字符。双字节字符也用过char类型来操作(这也是我们使用双字节时遇到的第一个怪现象)。wchar_t类型代表着Unicode字符。Unicode字符和字符串字面值由一个前缀字母L来编写例如: [cpp] view plaincopyprint? wchar_t  wch  L1;      // 2 bytes, 0x0031     wchar_t* wsz  LHello;  // 12 bytes, 6 wide characters   字符在内存中是如何存储 单字节字符串在内存中是以一个字符接着一个字符用单字节的0来结束的形式存储的。 例如Bob是这样存储的: 42   6F   62   00  B o b EOS Unicode 版本的,LBob,是这样存储的: 42 00   6F 00   62 00   00 00  B o b EOS 以0x0000(0的Unicode编码形式)作为结束标记. 双字节字符串初看起来像单字节字符串但是当我们以后使用字符串操作函数和利用指针遍历字符串时将看到他们的细微区别。字符串(nihongo)采用以下形式存贮(下面表中的LB代表 lead bytes,TB代表trail bytes): 记住ni值并不是被解释为0xFA93这一值。而是93和FA两个值以那种字节序在一起而被编码为ni.(因此在一个大端格式(Big-endian)的CPU上这些字节仍然按上述顺序) 字符串处理函数的使用 我们已经见过C风格字符串函数像strcpy(), sprintf(), atol()等等。这些函数只能用于处理单字节的字符串。标准库中有他们的只能用于处理Unicode字符串的版本诸如wcscpy(), swprintf(), _wtol(). 微软也在C运行库C runtime library中增加了这些函数处理多字节字符串的版本。strxxx()这类函数对应的DBCS版本取名为_mbsxxx().如果你遇到了DBCS字符串如果你的软件是安装在日文、中文或者其他使用DBCS的语言情况下你会遇到的你应该总是使用_mbsxxx()函数因为他们接受SBCS字符串(一个DBCS字符串可能仅仅包含单字节字符这就是_mbsxxx()函数可以处理SBCS字符串的缘故)。 让我们来看一个典型的字符串来解释字符串处理函数不同版本的必要性。回到上文讲到的Unicode字符串LBob:  42 00   6F 00   62 00   00 00  B o b EOS 因为x86系列CPU是小端格式(little-endian),值0x0042在内存中形式为42 00.你预见到了把这个字符串传递给函数strlen()的问题了吗?函数将看到头字节42然后00而00恰好是字符串结束标志函数将返回1.相反,将Bob传递给函数wcslen(),将变得更糟。wcslen()会首先看到0x6F42,然后是0x0062继而一直读下去直到碰到了00 00序列或者引起了GPF. 这里我们涉及到了strxxx()和wcsxxx()的对比。他们的区别又是什么呢?他们的区别至关重要与在DBCS字符串中的合理的遍历密切相关。下文将讲述字符串的遍历然后再回到二者的对比上来。 字符串中合理的遍历和索引 我们之中的大部分人都是伴着SBCS字符串而成长起来的我们习惯了利用指针通过和--操作符来遍历一个字符串。我们也习惯于用数组来获取字符串中的字符。这两种方式在SBCS和Unicode字符串下用起来十分完美因为字符都是相同长度的编译器会成功返回我们想要的字符。 但是当你遇到了DBCS字符串时为了代码的正常运行你必须改掉这种习惯。 这里有两条利用指针遍历DBCS字符串的原则。破坏了这些原则将导致你大部分与DBCS相关的漏洞(bugs)。 1.不要使用操作符来向前遍历除非你一直检查字符串的头字节。 2.永远不要用--操作符来向后遍历。 我先解释原则2因为很容易找到一个破坏它的而不知不觉的例子。假设你有一个程序在自己的目录里存贮配置文件而你把安装目录写入了注册表里。在运行时你读取安装目录附加上配置文件名然后尝试读取它。再假设你的安装目录是C:\Program Files\MyCoolApp要建立的文件名是C:\Program Files\MyCoolApp\config.bin,在你测试的时候它工作的很完美。 现在假想以下是你用来建立文件名的代码: [cpp] view plaincopyprint? bool GetConfigFileName ( char* pszName, size_t nBuffSize )    {    char szConfigFilename[MAX_PATH];             // Read install dir from registry... well assume it succeeds.             // Add on a backslash if it wasnt present in the registry value.        // First, get a pointer to the terminating zero.    char* pLastChar  strchr ( szConfigFilename, \0 );             // Now move it back one character.        pLastChar--;               if ( *pLastChar ! \\ )            strcat ( szConfigFilename, \\ );             // Add on the name of the config file.        strcat ( szConfigFilename, config.bin );             // If the callers buffer is big enough, return the filename.        if ( strlen ( szConfigFilename )  nBuffSize )            return false;        else            {            strcpy ( pszName, szConfigFilename );            return true;            }    }   虽然这是一分很安全的代码但是遇到一些特殊的DBCS字符时仍将会出错。来分析下为什么会这样假设一个日本用户将你的安装目录改为.以下是目录名在内存中的存贮形式: 当GetConfigFileName()检查反斜杠时它会检查安装目录的最后一个非0字节来判断是否等于\\如果没有则添加上去。运行的结果是返回错误的文件名。哪儿出错呢?看看以蓝色高亮显示的反斜杠。反斜杠字符的值是0x5C.的值是83 5C而上述代码误将它的后随字节当做了一个独立字符。正确的向后遍历方法是使用注意到DBCS字符特点的函数使指针移动正确数目的字节。下面是正确的代码指针移动部分用红色标记了。 [cpp] view plaincopyprint? bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )    {    char szConfigFilename[MAX_PATH];             // Read install dir from registry... well assume it succeeds.          // Add on a backslash if it wasnt present in the registry value.        // First, get a pointer to the terminating zero.       char* pLastChar  _mbschr ( szConfigFilename, \0 );          // Now move it back one double-byte character.        pLastChar  CharPrev ( szConfigFilename, pLastChar );        if ( *pLastChar ! \\ )            _mbscat ( szConfigFilename, \\ );           // Add on the name of the config file.        _mbscat ( szConfigFilename, config.bin );         // If the callers buffer is big enough, return the filename.        if ( _mbslen ( szInstallDir )  nBuffSize )            return false;        else            {            _mbscpy ( pszName, szConfigFilename );            return true;            }    }   修改后的函数使用了CharPrev() API来使pLastChar向后移动一个字符这样就可能移动两个字节如果字符串以双字节字符结尾。在这个版本中假设的情况会运行正常因为头部字节将永远不等于0x5C。 你可以合理想象下破坏原则1的方式。举个例子你通过判断字符:出现的次数验证用户输入的一个文件名是否合法。如果你使用而不是CharNext()来遍历,你可能会产生错误如果碰巧遇到后随字节等于:的字符。 和原则2相关的使用数组索引的原则: 2a.永远不要使用减法来计算字符串的索引。 破坏这个原则的代码和破坏原则2的代码很相似。例如pLastChar像下面这样使用时 [cpp] view plaincopyprint? char* pLastChar  szConfigFilename [strlen(szConfigFilename) - 1];   这同样的破坏了原则因为计算索引时使用减1这等于指针向后移动一个字节这破坏了原则2. 再谈strxxx()和_mbsxxx()的对比 现在应该明白_mbsxxx()这类函数的必要性了。Strxxx()不知道DBCS字符而_mbsxxx()函数了解.如果你调用将返回错误结果 但是_mbsxxx()将在末尾识别出双字节字符返回实际上指向反斜杠的指针。 关于字符串函数的最后一点strxxx()和_mbsxxx()函数取或者返回长度均以char为单位。 因此对于一个包含3个双字节字符的字符串_mbslen()将返回6.Unicode函数以wchar_t为单位返回长度例如wcslen(LBob)返回3. Win32 API中的MBCS和Unicode 两套API 即使你从没有注意到但是Win32中每一个处理字符串的API和消息都有两个版本. 一个接受MBCS字符串另一个接受Unicode字符串。举个例子并没有SetWindowText这个API,相反有SetWindowTextA()和SetWindowTextW().后缀A(对于ANSI)指示MBCS函数后缀W(对于Wide)指示Unicode版本。 当你建立一个Windows应用程序你可以选择使用MBCS或者Unicode版本的API.如果你使用VC应用程序向导并且从未接触过编译器设置的话你使用的一直是MBCS版本。那么为什么我们写下SetWindowText而事实上又没有这个名字对应的API呢?在winuser.h头文件中包含了一些#define开头的宏如下: [cpp] view plaincopyprint? BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );    BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString );    #ifdef UNICODE    #define SetWindowText  SetWindowTextW    #else    #define SetWindowText  SetWindowTextA    #endif   当以MBCS API建立时UNICODE就没有定义因此编译器看到: [cpp] view plaincopyprint? #define SetWindowText  SetWindowTextA   并将所有调用SetWindowText()的地方用真正的API,SetWindowTextA来替换掉。(注意你可以直接调用函 数SetWindowTextA和SetWindowTextW,尽管你很少需要这样做.) 因此如果你想要把Unicode API设定为默认的话你可转到编译器设置项,从预定义符号表中移除_MBCS 符号同时添加上UNICODE和_UNICODE.(你应该把两个都加上因为不同头文件使用不同符号.)但是如 果你直接使用char作为字符串的话将会遇到麻烦。 考虑以下代码: [cpp] view plaincopyprint? HWND hwnd  GetSomeWindowHandle();    char szNewText[]  we love Bob!;    SetWindowText ( hwnd, szNewText );   当编译器将SetWindowText用SetWindowTextW替换后代码变为: [cpp] view plaincopyprint? HWND hwnd  GetSomeWindowHandle();    char szNewText[]  we love Bob!;    SetWindowTextW ( hwnd, szNewText );   看到问题所在呢吗?我们向需要Unicode字符串的函数传递了一个单字节字符串。解决这种问题的第一种方法就是在字符串变量定义的周围使用#ifdef宏: [cpp] view plaincopyprint? HWND hwnd  GetSomeWindowHandle();    #ifdef UNICODE    wchar_t szNewText[]  Lwe love Bob!;    #else    char szNewText[]  we love Bob!;    #endif    SetWindowText ( hwnd, szNewText );   你肯定会为在每个字符串代码周围加上这些宏而头疼不已。问题的解决方案就是使用TCHAR. TCHAR 大救星 TCHAR是一种允许你为MBCS和Unicode应用使用同一分代码的字符类型,它不需要在你整个代码中写这些零乱的#define宏。TCHAR的一种定义如下: [cpp] view plaincopyprint? #ifdef UNICODE  typedef wchar_t TCHAR;  #else  typedef char TCHAR;  #endif   因此一个TCHAR在MBCS工程中是char类型在Unicode工程中是wchar_t类型。这里还有一个_T()宏来处理Unicode字符串字面值所需的L前缀。 [cpp] view plaincopyprint? pre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcppprepre namecode classcpppre namecode classcpppre namecode classcpppre namecode classcpppre   [cpp] view plaincopyprint? span stylecolor:#000000;/spanpre namecode classcpp#ifdef UNICODE    #define _T(x) L##x    #else    #define _T(x) x    #endif   ##是用来连接两个参数的预编译操作符。无论何时在你代码中有字符串字面值时使用_T宏那么在Unicode工程中就会添加上L前缀。 [cpp] view plaincopyprint? p/ppre namecode classcpppre namecode classcppTCHAR szNewText[]  _T(we love Bob!);   正如有隐藏SetWindowTextA/W的宏一样也有一些宏可以用来代替使用strxxx() 和_mbsxxx()字符串函数.例如你可以使用_tcsrchr宏来替换strrchr()或者_mbsrchr或者wcsrchr._tcsrchr根据是否定义了_MBCS或者UNICODE符号而被展开为具体对应的函数就像SetWindowText那样。 不止strxxx()函数由TCHAR宏,还有很多,例如_stprintf()( 替换Sprintf()和swprintf() ),_tfopen()( 替换fopen()和_wfopen()  ).所有的宏定义列表在MSDN中Generic-Text Routine Mappings主题下可查. String和TCHAR typedef 由于Win32 API文档以函数名列举函数(l例如,SetWindowText),所有的字符串均以TCHAR形式给定。(例外之处是xp系统中的仅适用于Unicode的API) 下列是你可在MSDN中看到的常见typedef: 何时使用TCHAR和Unicode 那么讲了这么多你可能会想为什么我要使用Unicode?我已经单单使用char好多年了 下面三种情况使用Unicode将会颇有益处: 1.你的程序仅仅在Windows NT系统上运行。 2. 你的程序要处理长度超过MAX_PATH的文件名。 3.你的程序使用了Windows XP中新的API而这些APi没有区分的A/W版本。 大部分的Unicode API都没有在Windows 9x上执行所以如果你只想你的程序在9x上运行那你就要坚持使用MBCS API.(微软公司一些新的叫做MicroSoft Layer的库允许在9X上使用Unicode API但是我没有使用过我不知道执行情况如何.)但是既然NT系统内部所有的都采用Unicode,使用Unicode API可以提高你程序运行的速度。每次你向MBCS API传递一个字符串时系统将字符串转换为Unicode型同时调用相应的Unicode API。如果一个字符串返回了那么操作系统将其转换后再返回。尽管这些转换操作都做了很大程度的优化来尽可能减小影响但是鉴于其影响运行速度还是应该避免。 NT 只有在你使用Unicode API时才允许使用超过MAX_PATH长度的文件名。使用Unicode API 的好处一方面就是你的程序将自动处理不同用户键入的任意语言。那么当一个用户可同时键入一个英文的、中文的、日文的文件名而你可以不用编写任何特别处理的代码因为它们对你而言都是Unicode字符。 最后随着Windows 9x的下线微软好像已经废除了MBCS  API。例如SetWindowTheme() API,有两个字符串参数但是只有Unicode版本。使用Unicode工程将简化你的字符串处理因为你也不想在MBCS和Unicode之间来回转换。 而且即使你现在没有建立Unicode工程你也应该一直使用TCHAR和相关的宏。 不仅仅因为这样可以保证你代码的DBCS安全性同时当未来某个时候你想建立Unicode工程时你只需改动一下你编译器的设置 原文地址:http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara 下一部分原文地址:http://www.codeproject.com/Articles/3004/The-Complete-Guide-to-C-Strings-Part-II-String-Wra 下一部分译文还在翻译中...
http://www.sadfv.cn/news/270943/

相关文章:

  • 响应式网站模板分享wordpress apache ssl
  • 要想让别人网站卖我的东西怎么做灵台门户网站建设
  • 做产品推广得网站wordpress展示类主题
  • 门户网站制作服务博客网站哪个权重高
  • 网站导航栏如何优化know how wordpress
  • 网站正能量晚上在线观看wordpress 被搜索引擎
  • 珠海网站建设兼职建设网络道德教育网站的有效措施有
  • 可以注册的网站飞言情做最好的小说网站
  • 怎么免费建设个人网站网站开发部门工作职责
  • 开办网站备案深圳市建设股份有限公司
  • 企业网站建设要求简洁又有高级感的ppt
  • 360阻止建设银行网站找广告设计
  • 贵阳手机网站建设公司电脑接单做任务平台
  • 杭州建设银行网站电商资讯网站有哪些
  • 网站开发 注意事项如何查询网站以建设多长时间
  • 沧州网站建设专业定制现代营销手段有哪些
  • 个人网站备案好麻烦哦潍坊网站建设服务
  • 轻淘客网站怎么做新东家网站建设
  • 做网站买流量专业做网吧的公司
  • 最好的微网站建设价格网页制作用什么工具
  • 网站 微信小程序怎么做网站建设必须要服务器么
  • 无锡网站建设 微信你认为视频网站如何做推广
  • 做网站都需要哪些信息天河建设网站技术
  • 电商网站建设浩森宇特网站首页开发收费
  • 公司网站建设一条龙政务服务网站建设运行情况
  • 网站后台模板 jquerywordpress加载转圈
  • 教育网站建设的策划方案汕头网站推广排名
  • 网站开发公司徐州wh网站建设
  • 网站建设 dw厦门高端网站建设
  • 青岛网站建设公司报价做笑话网站需要什么