热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

揭开字符的面纱(二)

上面一节提到了字符的表示方式,这一节主要讲他们的由来以及微软给出的解决方案。在《Windows核心编程中》有提到,从WindowsNT开始,

上面一节提到了字符的表示方式,这一节主要讲他们的由来以及微软给出的解决方案。
在《Windows核心编程中》有提到,从Windows NT开始,Windows的所有版本都完全用Unicode来构建。这个意思就是说,即使你用的是ASCII字符或者ASCII字符串(一个字符一个字节),都将在内部转换成Unicode字符。在大部分的Windows的API中都有xxxxxxA、xxxxxxW以及xxxxxxEx等三个前缀相同的版本,后缀为A表示使用的ANSI版本(不是ASCII),后缀为W表示使用Unicode版本(w的意思是wide),以及中间兼容版本Ex。若使用_UNICODE宏和UNICODE宏,Ex就就用Unicode版本,反之则使用ANSI版本,这是微软想到解决兼容的一种办法。

自从VC6.0开始,就已经支持UNICODE字符集,但是VC6.0默认的是“多字节字符集”(MBCS),使用UNICODE字符集需要自行在项目中定义UNICODE宏和_UNICODE宏;然而VS.NET2002以及更高版本默认的却是UNICODE字符集,即定义了UNICODE宏和_UNICODE宏,除非你在项目属性中人工指定使用“多字节字符集”(MBCS),那样就不会定义UNICODE宏和_UNICODE宏。

VS2013的MFC更是完全废除了MBCS,使用MBCS会给编译错误信息:MBCS is depreciated。

之前有提到过ANSI字符集,也有很多套,但是计算机怎么知道要用哪套字符集呢?于是提出了一套“治标不治本”的方案,这就是“ANSI代码页”。每种字符集规定一个数字作为唯一标识符,叫做“代码页”,更换这个唯一标识符就切换字符集。例如ASCII的代码页是437,latin-1的代码页是1252,GB2312-80的代码页是20936,GBK的代码页是936,BIG-5的代码页是950,GB18030的代码页是54936等等。

起初Windows就是用“ANSI代码页”切换方案,字符串用char数组来存储,叫做“多字节字符集(MBCS)”,从上一篇知道,这么叫的原因是因为有些字符不止占一位,一个GBK汉字可能占两位。

切换代码页是治标不治本,可能在这台计算机上能够编译成功,但是到了别人电脑,使用了不一样的代码页,就只能看到一堆乱码。于是为了统一文字,Unicode字符集出现了。【ISO国际标准】根据ISO的C标准和C++标准,字符类型有两种:一种叫做“窄字符”(narrow character),用char表示,每个单位占一个字节;另一种叫做“宽字符”(wide character),用wchar_t表示,每个单位占的字节数必须多于char,但没有规定具体占几个字节。窄字符和宽字符的表示方式分别是:char s[] = “narrow character” 和 wchar_t ws[] = L"wide character" 。


微软在C标准之外,私自定义了“C风格窄字符串”和“C风格宽字符串”:

// 这是C风格窄字符串,以'\0'结尾的窄字符数组
#define CONST const
typedef char CHAR;
typedef CHAR *NPSTR, *LPSTR, *PSTR;
typedef CONST CHAR *LPCSTR, *PCSTR;

// 这是以L'\0'结尾的宽字符数组
#define CONST const
typedef wchar_t WCHAR;
typedef WCHAR *NWPSTR, *LPWSTR, *PWSTR;
typedef CONST WCHAR *LPCWSTR, *PCWSTR;

为了在ANSI字符集和Unicode字符集之前切换,还定义一种TCHAR字符类型,在中定义如下:

typedef wchar_t WCHAR;
#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
#else
typedef char TCHAR, *PTCHAR;
typedef LPSTR PTSTR, LPTSTR;
typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR;
#endif

还定义了TEXT宏:

#ifdef UNICODE
#define __TEXT(quote) L##quote
#else
#define __TEXT(quote) quote
#endif
#define TEXT(quote) __TEXT(quote)

头文件中,还定义了_T宏和_TEXT宏:

#ifdef _UNICODE
#define __T(x) L ## x
typedef wchar_t TCHAR;
#else
#define __T(x) x
typedef char TCHAR;
#endif
#define _T(x) __T(x)
#define _TEXT(x) __T(x)

ISO的C和C++标准也有对应的窄字符集函数printf、strcat、strcmp和宽字符集函数wprintf、strcat、strcmp等等。微软也私自在中宏定义了这些函数的TCHAR风格类型:

#ifdef _UNICODE
#define _tprintf wprintf
#define _tcscmp wcscmp
#define _tcscat wcscat
#else
#define _tprintf printf
#define _tcscmp strcmp
#define _tcscat strcat
#endif

跨平台应该注意:

  • 【ISO国际标准】ISO的C标准和C++标准只规定了窄字符char为一个字节,宽字符wchar_t的字节数大于char。没有规定wchar_t具体占几个字节。没有TCHAR这个东西,不存在头文件。
  • 【微软方案】在微软的编译器中,char每个单位占一个字节,表示ANSI字符集;wchar_t占两个字节,表示UTF-16小端模式。可以用TCHAR类型(在头文件中),并用是否定义UNICODE宏和_UNICODE宏来切换。
  • 【Linux通常情况】在大多数Linux下的编译器中,char每个单位占一个字节,通常表示UTF-8字符集;wchar_t占四个字节,表示UTF-32字符集,大小端与CPU相关。没有TCHAR这种东西。

以上就是今天的总结,希望大家能够指出错误,定会加以改进。

推荐阅读
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 深入解析:Synchronized 关键字在 Java 中对 int 和 Integer 对象的作用与影响
    深入探讨了 `Synchronized` 关键字在 Java 中对 `int` 和 `Integer` 对象的影响。尽管初看此题似乎简单,但其实质在于理解对象的概念。根据《Java编程思想》第二章的观点,一切皆为对象。本文详细分析了 `Synchronized` 关键字在不同数据类型上的作用机制,特别是对基本数据类型 `int` 和包装类 `Integer` 的区别处理,帮助读者深入理解 Java 中的同步机制及其在多线程环境中的应用。 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 在Linux系统中,`inet_pton` 和 `inet_ntop` 是两个重要的IP地址转换函数,它们能够实现IP地址在“点分十进制”和“整数”格式之间的相互转换。特别是 `inet_pton`,它不仅支持IPv4,还支持IPv6地址的转换,广泛应用于网络编程中,确保了不同格式IP地址的高效处理和兼容性。本文将详细探讨这两个函数的内部实现机制及其在网络编程中的具体应用。 ... [详细]
  • 本文详细介绍了在MySQL中如何高效利用EXPLAIN命令进行查询优化。通过实例解析和步骤说明,文章旨在帮助读者深入理解EXPLAIN命令的工作原理及其在性能调优中的应用,内容通俗易懂且结构清晰,适合各水平的数据库管理员和技术人员参考学习。 ... [详细]
  • 如何在JavaScript中实现字符到ASCII码的转换 ... [详细]
  • Python 编程技巧:实现字符串中字符大小写的转换 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
author-avatar
素材火
优质网页素材http://www.sucaihuo.com/
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有