第四部分:字符串
一、字符串使用
在C/C++中字符串不是一个基本数据类型,而是体现为字符数组。
字符串的使用要考虑储存管理方式、操作开销、本地化等问题。
二、字符串类
STL提供了字符串类的实现。如果不使用STL的话可以自己实现字符串类。
使用字符串类之前必须了解它的性能开销。比如字符缓冲区是不是只读的,是不是使用了copy-on-write优化,是以引用传递还是以值传递。
字符串复制通常比int或者float等复制慢,因为其长度可变。strcmp和strcpy等操作都要检测
\0
空字符。
有一种情况是推荐使用字符串类的,那就是路径Path类。因为可以很方便地提取文件名、文件扩展名、目录,而且还方便跨平台。
三、唯一标识符
游戏对象需要某种唯一标识方法,游戏资源也需要唯一标识符,方便引擎寻找和操控。
可以使用字符串做标识符。游戏资产用文件路径作为标识符。游戏对象通常用一些清晰明了的名字做标识符。
比较标识符的速度必须很快,strcmp()
是完全达不到要求的。可以使用字符串散列标识符。
字符串散列标识符:
字符串散列把字符串映射成整数,把实际字符串储存至散列表。
散列码能像整数一样比较。操作很迅速。
可以通过散列码取回原来的字符串。(一般用于debug)
这种散列字符串,虚幻引擎称为name。
有发生碰撞的几率,但是极小。(32位散列码能表示40亿个值)
实现方法:
大多数游戏引擎会在运行时进行散列。
也可以利用简单工具在预处理中散列字符串以便在例如switch-case等要求编译时常量的情况下使用字符串标识符。
散列字符串并加进全局字符串表的过程称为字符串扣留(string interning)。字符串扣留的速度缓慢,最好只把字符串扣留一次,然后存储备用。
虚幻引擎把字符串标识符和相应的C风格字符串封装成一个类。(名为FName)
如果把字符串放在调试内存中,最终发行版代码应该永不依赖那些字符串。
四、字符编码
ASCII:
美国信息交换标准代码。基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。只有128个字符。
MBCS(多字节字符集):
一些使用多于1字节的字符集,包括GBK、Big5等,通常不能实现多国文字混合使用。
Unicode:
Unicode的目标是一套字符集包揽各种文字。其编码格式(UTF-8/UTF-16)可以容许一个字符串内包含多国字符。
Unicode只是从数字和字符之间的逻辑映射的概念编码。并不是存储/传输格式编码。
UTF-32:
UTF-32是固定长度的编码(4个字节)。 UTF-32足以容纳所有Unicode字符。所以直接存储Unicode编号即可。
UTF-32缺点是占用较多空间。
UTF-16:
Unicode编码0-FFFF之间的字符,UTF-16使用2字节存储。(和UTF-32一样直接存储Unicode编码)
Unicode编码10000-10FFFF的字符使用4个字节存储。
xxxxxxxx xxxxxxxx
110110xx xxxxxxxx 110111xx xxxxxxxx
UTF-16大部分字符都以固定长度的字节(2字节)储存,编码很简单。
UTF-8:
UTF-8是Unicode的另一种可变长度字符编码实现。UTF8编码中每个字符占1-3字节。
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8向下兼容ASCII编码,单字节UTF8编码等同ASCII编码。所以ASCII字符串都是合法的UTF8字符串。
WINDOWS的Unicode编码:
在Windows下宽字符(WCS)UTF-16一般用wchar_t
数据类型表示,而char
一般用于表示ANSI字符。
- 在Windows下字符串的C标准函数都有WCS和MBCS版本:
ANSI | WCS | MBCS |
---|---|---|
strcmp() | wcscmp() | _mbscmp() |
strcpy() | wcscpy() | _mbscpy() |
strlen() | wcslen() | _mbslen() |
- Window也提供不同编码格式字符串的转换函数。例如
wcstombs()
等。