前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows 编程中的字符编码

Windows 编程中的字符编码

作者头像
Harper
发布2021-07-27 10:04:34
9360
发布2021-07-27 10:04:34
举报
文章被收录于专栏:Harper的碎碎念

经常在写代码的时候需要处理宽字符,ASCII 字符,在代码中看到 wchar、char 等等。一般都是处理一个方法的时候发现需要的是某字符串,然后这边有什么字符串,之后查一个转换方法。还有对于 Unicode 、ANSI 这些不太分得清,所以花了一点时间看了一看。做个小结。

编码介绍

ANSI

ANSI(American National Standards Institute) 其实并不算是一种固定编码,可以理解为在不同国家,有着不同的解释。例如在中国大陆,ANSI 编码指的就是 GBK 编码,在台湾地区指的是 BIG5 编码。所以一个场景下这种编码是有问题的,比方说一个保存为 ANSI 编码的文件,在不同区域的系统下,用记事本打开就会有问题,因为对文本的解释是不同的。例如在中国的系统上保存,其实就是 GBK 编码,然后在美国的系统上打开,会被当做 ASCII 编码来解释,就会出现问题。看不到想要的内容。(注:所以《 Windows 核心编程(第五版)》(下称《核心编程》)2.1节作者说到:调用 strlen 会返回“以 0 结尾的一个 ANSI 单字节字符数组”中的字符数,这个表述是不准确的,之所以这么说是因为作者所在的国家显然是 ASCII 编码,但是拿到中文这里说就不恰当,可以说是作者的锅也可以说是译者的锅。所以此书第二章所有讲到 ANSI,都可以理解为 ASCII 编码)

Unicode

Unicode 标准(使用多字符编码)解决了 ASCII 编码这种单字符编码无法表示一些包含特别多字符的问题。官方的一段解释The Unicode Standard provides a unique number for every character, no matter what platform, device, application or language.,其实就是把每个字符作为一个具体数字 。对于 Unicode 标准,存在多种编码,例如:UTF-8 编码,UTF-16 编码等等。UTF(Unicode Transformation Format),指的是 Unicode 转换格式。

UTF-8

以下引用《核心编程》原文:

UTF-8 将一些字符编码为 1 个字节(可以说就是那些 ASCII 字符),一些字符编码为 2 个字节,一些字符编码为 3 个字节,一些字符编码为 4 个字节。根据 Unicode 的数字不同来区分应该编码为几个字节,属于变长字节编码。这样的好处是显而易见的,就是节省空间,坏处也是显而易见的,处理一些字符编码比较复杂的文本,显然效率会差,至少要不断判断是几个字节,计算长度就比较麻烦。

UTF-16

UTF-16 就比较鸡贼了,如果细说就要扯到辅助平面和基本文字平面了,感觉意义都不是很大。简单理解就是一般字符(文字基本都是这个范畴)编码为 2 个字节,不一般的编码为 4 个字节(也就是 2 个 2 字节)。关于 UTF-16 连《核心编程》都没说,可见作者也是非常鸡贼了。

UTF-32

UTF-32 这个算是最省事了,把 Unicode 值用 32 位无符号整数表示就得到了 UTF-32 的编码了。缺点也是显而易见的,贼占地方。

BOM头

经常在 Code Page 中看到带 BOM 头和不带 BOM 头。这个跟编码的大小端有关。对于这种多个字节的编码存在一个大小端的问题。如何来区分编码的大小端。Unicode 标准推荐使用一个 BOM(Byte Order Mark)来做区分。BOM 的字符编码是0xFEFF,这个叫做零宽无中断字符,这也解释了为什么你在文件里边去掉和添加 BOM 头都不会影响排版。所以 BOM 头的存在可以帮助判断文本的编码的大小端,如果没有 BOM 头的文本,在跨系统使用的时候,编辑器的实现可以做出两种做法:1. 会根据系统是大小端强行解释,这样的问题是一旦两个系统不一致,看到的内容也就完全不对了;2. 根据里边的数据,做一个判断,因为当大端被解释成小端有可能会出现 Unicode 中不存在的字符(如 BOM 头这个字符,0xFEFF存在,0xFFEF不存在)。在我看来显然应该是第一种做法。具体理由按下不表了。

数据类型

char

1 个字节(8 bit)。用来表示 ASCII 编码。

wchar_t

2 个字节(16 bit)。用来表示 Unicode 字符(UTF-16)。当写出wchar_t c = L'A';这行代码的时候,编译器会把L后边的东西用 UTF-16 来编码。值得一提的是wchar_t早期的 Microsoft 编译器并不支持。在那个上古时期有这样一个定义typedef unsigned short wchar_t。后来支持以后,编译器搞了一个编译开关/Zc:wchar_t,有这个的才在编译器定义这个数据类型,现在新建项目的时候会默认开启了。

CHAR、WCHAR

按照《核心编程》的说法:

为了与 C 语言稍微有一些区分,Windows 开发团队希望定义自己的数据类型。

  • CHAR:typedef char CHAR
  • WCHAR: typedef wchar_t WCHAR
  • 指针:
代码语言:javascript
复制
// Pointer to 8-bit character(s)
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR
// Pointer to 16-bit character(s)
typedef WCHAR *PWCHAR;
typedef WCHAR *PWSTR;
typedef CONST WCHAR *PCWSTR

TCHAR

TCHAR c = TEXT('A')。这个可以理解为万能类型,之所以这么说,可以看一下它的定义

代码语言:javascript
复制
#ifdef UNICODE

typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define_TEXT(quote) L##quote

#else

typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define_TEXT(quote) quote

#endif

#define_TEXT(quote)_TEXT(quote)

所以看你的项目是否定义了 UNICODE 宏来决定 TCHAR 的类型,当然这个 UNICODE 宏还会影响 Windows API 调用函数版本的选择,后边细说。所以会看到大批文章告诉你解决什么编不过的问题都直接让你用 TCHAR 和 TEXT()。但我觉得并没有太大意义,至少我暂时想不到需要这两个版本都支持的场景。项目使用哪种数据类型明确一点会比较好,会影响到效率,后边细说。

函数

对于 Windows API 微软都会提供两个版本的例如 CreateWindowExWCreateWindowExA,一个是宽字符版本,一个是单字符版本。当然如果你用CreateWindowEx,你会发现再配合 TCHAR 这套,显然也可以正常使用。

代码语言:javascript
复制
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW 
#else
#define CreateWindowEx CreateWindowExA
#endif

就是因为这个缘故。所以上边我说会影响到函数版本的选择。而效率问题,在 Windows Vista 上(当然可以理解为之后的版本也都如此) A 版本的函数其实只是一个转换层,将传入的 ASCII 字符转换成 Unicode 字符,然后调用 W 版本。所以这中间会有一个分配内存的过程,显然会有一个效率上的问题。所以其实现在写代码,非常推荐统一使用宽字符版本。

另外除了 Windows API 之外,C 运行库,也有类似的操作。

代码语言:javascript
复制
#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif

只不过使用的是 _UNICODE 宏。所以不想让工程出现编码的混乱,显然 UNICODE、_UNICODE 是要成对出现的。事实上,现在用 Visual Studio 新建工程的时候,默认这两个都会定义上的。

跨平台的坑

对于 wchar_t 在 Windows 平台是 UTF-16 编码,是 2 个字节的长度。而在 Linux 上是 4 个字节的长度,GCC 编译的时候会用 UTF-32 编码。这里边就会有一个不一致。要考虑编码转换问题。

最后

至此编程中需要的编码,大致了解清楚了。Windows 编程中,除非有特殊需要,否则一律使用宽字符是最好的选择。编码则选择 UTF-16 编码。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编码介绍
    • ANSI
      • Unicode
        • UTF-8
        • UTF-16
        • UTF-32
        • BOM头
    • 数据类型
      • char
        • wchar_t
          • CHAR、WCHAR
            • TCHAR
            • 函数
            • 跨平台的坑
            • 最后
            相关产品与服务
            区块链
            云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档