规范化的C++编程方法备忘录 本地化相关[写中文版软件必看](1)

1.字符和字符串

-编码:为了将人类定义的文字在计算机中能完整地表示,人们使用逻辑上连续存放的整数表示语句。受历史的影响(早期的计算机是没有考虑国际化的。那是为科学家和高校设计的,字符串存在的目的之一是用尽可能少的字符表达特定环境下的语义。知道意思即可,所以不乏大量的英文缩写、符号与数字的混合体),计算机被指定用0~127表示语言(仅英文、数字和标点符号,剩下的做编辑、控制符),成为ASCII。后来为了作图的目的扩展到了0~255。但非英语计算机厂商也拿扩展的码组改成自己的语言文字(如日语),成为OEM字符集。后来在计算机出口普及过程中不断遇到显示本地语言文字的问题。比如中文这种象形字就没法用几个单元字拼接的方法组成。解决的办法是用扩展过的几个字节一组存储一个字,然后在显示阶段作一次映射,从而显示成能被人所理解的符号。但当时的计算机内存容量都很小,有必要精打细算地存储,于是出现了多字节(multi-bytes)存储方式。multi-bytes的特点是ascii标准字符(0、英文、数字和标点符号、编辑符)保持为一个字节大小,非ascii标准字符从剩下的码中选出作为开始(leader-byte),跟着诺干个字节(tail-bytes)直到本字符结束。而选字的依据是当前系统(后来成为进程内甚至线程内)选定支持的语言编码集。因为在multi-bytes中每个字节严重依赖于前一个字节的属性,因此这种编码是流式的,只有知道一句的第一个字节才能逐个向后推导,反向推是不可能的。multi-bytes的优点就是节约内存,缺点就是不可随机遍历,从而使处理速度缓慢。当内存够用时就出现了多个字节一组的编码方式,目的是为了让一个单元能用于表示某种语言中定义的任意一个字符,同时也可以实现象ascii那样的随机遍历特性。比较常用的有unicode。其他的编码因不被内核原生支持,故不作讨论。

    总结一下3种原生支持的编码(oem非原生):

ascii: 一个字节代表一个字;支持随机遍历;只能显示编辑符、控制符、英文字母、数字、英制的标点符号;范围0~127

multi-bytes: 多个字节(1到5个)代表一个字;不支持随机遍历;理论上能显示任何字符;范围为0~ 2^40

unicode(1): 2个字节代表一个字;支持随机遍历;理论上能显示绝大部分字符;范围为0~ 2^16

 *附:multi-byte 的原生类型为BYTE,但当前TCHAR用于多字节时却为char,不影响使用。

-编程接口的使用:为了灵活地支持多种编码,防止出现兼容性问题,对字符串变量的类型作出如下限制:

 1-如果字符串只用在内存中,我们要把它定义为TCHAR的。

 2-如果字符串是用于保存文件、数据库的、把它定义为特定的类型。不管你定义的特定的类型是什么,都要保证形式上和TCHAR为两种不同的类型,应当进行编码转换(1.不是仅仅转换指针的类型!2.如果定义类型和TCHAR真实类型是一致的,默认直接识别即可,但形式上是“被转换过了的”)。

 3-如果你要提供给别人库文件,应当保证一致的接口!如果你只打算实现一种类型,你应该显示地指名类型!不要用TCHAR!如果你的确打算公开为TCHAR,你应该提供双接口!或者双版本!

 4-使用API的注意:有些是只提供一种接口的!如COM/ATL的标准api、DDK及WDK的接口指定使用WCHAR,请不要用TCHAR和其直接交换字符串(参照第2点)!还有的API只提供ASCII、只提multi-bytes接口。也不要用TCHAR和其直接交换字符串!(比如GetProcAddress的第2个参数)

 5-缓冲区长度的要求:要点一 字符个数不等于缓冲区长度,请使用真实的缓冲区长度算法。要点二 在不同的编码方式中转换时,如果不好计算目标字符串的缓冲区长度,那么至少应当假定当所有的源、目标字符串都是出于最坏编码转换情况下所需的目标缓冲区长度!

    例如源为MB,长度为n,目标UC,则当无法得知目标长度时,目标申请长度为 n*(2*sizeof(wchar_t))+1 (单位为 “个wchar_t ”!)。

    又如源为UC,长度为n,目标MB,则当无法得知目标长度时,目标申请长度为 n*5+1 (单位为 “个char ”!)。

   -第5点的附议:为了保证最大的兼容性,一个字符串缓冲区的长度应该在一个int的正方向范围/2内(16000多个字单元。ASCII/MB下为1字节,UC1下为一个字)。如果很长(例如一段文章),则必须自己设法实现size_t类型的处理器(这样的处理函数调用一次到返回往往要用较多的时间,本来就不适合做常规的字符串处理)。

2.字符和字符串的处理

 -首先设置线程的语言环境

  用API的可考虑SetThreadLocal;

标准C运行时的使用_tsetlocal / setlocal / msetlocal / wsetlocal。注意如果工程设置了静态连接运行时,你写的每个dll/lib都要调用一次

 -根据编码类型处理字符串。如果处理的对象是TCHAR字符串,还必须保证通用性;因为ASCII和multi-bytes的基本类型都是一个字节,如果处理的对象是ASCII字符串而不是multi-bytes的,应该作非法字符判断

 

TCHAR字符串处理的例子:对LPCTSTR类型的字符串lpszText查找空格字符,找到第一个后返回其偏移量的值:

注意这里的“lpszNext = _tcsinc(lpszNext)”不可写成“lpszNext++”!也不要随意对其进行按位优化

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏

unituniverse2

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值