正确使用 Unicode 和 MBCS 字符集

正确使用 Unicode 和 MBCS 字符集

在 Windows 下做开发,初学者经常面临字符集选择的问题。本文详细解释 MBCS 字符集和 Unicode 字符集的正确使用方法,以及为什么写程序要用 Unicode 字符集。同时对 UTF-8 做了简单介绍。

在程序中正确使用字符集

以 VC 为例,微软在 VC6.0 的时候,创建项目的默认字符集是 MBCS。从 VC2002(就是 VC7.0)开始,默认字符集就变为了 Unicode,直到今天。

为了减少字符编码造成的种种问题,请务必确保整个项目使用相同的字符集编码。比如,如果设置项目字符集为 Unicode,那么整个项目都要用 Unicode 方式处理字符串。具体方法:

1. 设置项目字符集

有两种方法设置项目字符集。

方法一,在项目属性中设置:

以 VC2010 Express 为例:在 Solution Explorer 右击项目 -> Properties,打开的属性窗口中,左侧选择 Configuration Properties / General 分类,右边将 Character Set 设置为 Use Unicode Character Set 即表示将项目设置为 Unicode 字符集,设置为 Use Multi-Byte Character Set 即表示将项目设置为 MBCS 字符集。

方法二,在代码中设置:

在代码的最顶部增加以下代码,表示程序使用 Unicode 字符集:

#define UNICODE
#define _UNICODE

在代码的最顶部增加以下代码,表示程序使用 MBCS 字符集:

#undef UNICODE
#undef _UNICODE

备注:_UNICODE 用于 C 运行库,UNICODE 用于 WINAPI。

2. 写程序时使用对应的字符集

对于 MBCS 字符集:char 定义字符(串),字符和字符串常量直接使用(例如:“Hello” 表示 MBCS 字符串),字符串函数可以使用 strlen、strcpy、strcmp 等。STL 可以使用 string。

对于 Unicode 字符集:wchar_t 定义字符(串),字符和字符串常量加 L 前缀(例如:L"hello" 表示 Unicode 字符串),字符串函数可以使用 wcslen、wcscpy、wcscmp 等。STL 可以使用 wstring。

如果需要同时适用 Unicode 和 MBCS 两种字符集编码:TCHAR 定义字符(串),字符和字符串常量加 _T("")(例如:_T("hello") 表示 Unicode/MBCS 自适应字符串),字符串函数可以使用 _tcslen_tcscpy_tcscmp 等。

具体每个字符串函数在不同字符集编码下的函数名,请参考微软的帮助文档。

通过示例展现 Unicode 比 MBCS 的优势

  • 实验环境 Windows 7 + VC2010 Express + EasyX_20220116。(在 Win10 下可以得到同样的结果)
  • 因为代码中涉及到英文中文韩文字符,需要将 .cpp 文件以 UTF-8 编码保存。方法:File -> Save xxx.cpp As…,在文件另存为对话框里,“保存”按钮右边有一个向下的箭头,点击后选择“Save with Encoding…”,同意覆盖原文件,然后 Encoding 选择 Unicode (UTF-8 with signature) - Codepage 65001,Line endings 不用调整,确定保存即可。

两个示例程序的具体设置与代码

第一个示例程序:

项目名称 TestUnicode
项目类型:Win32 Console Application
项目字符集:Unicode

#include <graphics.h>
#include <conio.h>int main()
{wchar_t s[] = L"厉害了我的国";initgraph(640, 480);settextstyle(24, 0, L"微软雅黑");outtextxy(10, 30, s);_getch();closegraph();return 0;
}

第二个示例程序:

项目名称 TestMbcs
项目类型:Win32 Console Application
项目字符集:MBCS

#include <graphics.h>
#include <conio.h>int main()
{char s[] = "厉害了我的国";initgraph(640, 480);settextstyle(24, 0, "微软雅黑");outtextxy(10, 30, s);_getch();closegraph();return 0;
}

原理解释

ASCII 码规定了每个字符一个字节,前 128 个属于常规 ASCII 码,后 128 个属于扩展 ASCII 码。常规 ASCII 码里面含有英文大小写字母、阿拉伯数字、常见标点符号等。扩展 ASCII 码里面是一些不常用的字符。

于是在过去,想要表示多语言的时候,就利用了扩展 ASCII 码不常用的特点,将两个连续的扩展 ASCII 码表示成其它语言。

例如中文的 GB2312 编码,将汉字分成 94 个区和 94 个位,区和位分别使用了扩展 ASCII 码的 161~254 这个范围。“中国”两字的区位码分别是 5448 2590,那么可以构造一个这样的程序(暂时忽略编译警告):

// 设置为 MBCS 字符集
#undef UNICODE
#undef _UNICODE#include <graphics.h>
#include <conio.h>int main()
{// “中”的区位码是 54 48,“国”的区位码是 25 90char s[] = {160 + 54, 160 + 48, 160 + 25, 160 + 90, 0};initgraph(640, 480);settextstyle(24, 0, "微软雅黑");outtextxy(10, 30, s);_getch();closegraph();return 0;
}

执行这个程序,可以成功的输出“中国”两个字。

这就是在 MBCS 字符集下中文的表示形式。

其他语言类似,比如韩文的 EUC-KR 编码(过去叫 KSC5601 编码),也用的两个扩展 ASCII 码,并且范围也是 0xA1-0xFE。台湾地区的 BIG5 编码也覆盖了这个范围。那么问题来了:两个扩展 ASCII 码,究竟表示中文、韩文还是繁体中文或者别的语言?

这取决于操作系统的系统区域(locale)设置,
当 locale 设置为简体中文,那么两个连续的扩展 ASCII 码就会根据 GB2312 编码解析;
当 locale 设置为韩文,那么两个连续的扩展 ASCII 码就会根据 EUC-KR 编码解析。

由此可知:

  1. 系统区域设置错误,MBCS 字符集的字符串就无法正确显示。
  2. MBCS 字符集无法实现多语言混合显示。

当编码与 locale 不匹配的时候,就会出现“乱码”。

Unicode 字符集整合了全世界所有语言的文字,任何语言的任何一个文字,在 Unicode 编码中都有唯一的值对应。因此不再需要设置“系统区域(locale)”,也就不会产生“乱码”了。

就像前面的实验看到的那样,采用 Unicode 字符集的程序,无论是同时显示多少种语言,无论在什么语言的操作系统上执行,都可以正常显示。

该文章会更新,欢迎大家批评指正。

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/98891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无图形化界面使用wireshark抓包分析数据

1. 解决Wireshark的权限不足问题 当普通用户身份运行Wireshark时&#xff0c;会遇到权限不足的问题。原因在于dumpcap需要root权限才能正常工作。以下是解决此问题的步骤&#xff1a; 创建用户组 我们将创建一个名为wireshark的用户组&#xff1a; sudo groupadd wireshark 更…

leetcode 70.爬楼梯、322.零钱兑换、279.完全平方数

70. 爬楼梯(进阶版) 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个或m个(m<n)台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. …

大语言模型学到什么

背景&#xff1a; 这篇文章是对《LANGUAGE MODELS REPRESENT SPACE AND TIME》论文的翻译加解读。之所以选这篇文章是因为最近在研究大模型的可解释性&#xff0c;以及基于可解释性对大模型的下游任务适配做训练级别可控性增强研究。其实总结成两句话就是&#xff1a; 1.大模…

Spring【@Resource、@Autowired+lombook+Bean的生命周期】

Resource 和 Autowired 的区别 在Spring中找Bean的两种方式&#xff1a;①先根据类型查找②再根据名称查找 Autowired先根据类型查找&#xff0c;再根据名称查找【根据上述查找结果不唯一&#xff0c;再添加一个 Qualifier(value“”)&#xff0c;就可以查找】 Resource先根据名…

【12】c++设计模式——>单例模式练习(任务队列)

属性&#xff1a; &#xff08;1&#xff09;存储任务的容器&#xff0c;这个容器可以选择使用STL中的队列&#xff08;queue) &#xff08;2&#xff09;互斥锁&#xff0c;多线程访问的时候用于保护任务队列中的数据 方法&#xff1a;主要是对任务队列中的任务进行操作 &…

【C++ 学习 ㉖】- 布隆过滤器详解(哈希扩展)

目录 一、布隆过滤器的简介 二、布隆过滤器的实现 2.1 - BloomFilter.h 2.2 - test.cpp 一、布隆过滤器的简介 布隆过滤器&#xff08;Bloom Filter&#xff09;是由 Burton Howard Bloom 在 1970 年提出的一种紧凑型的、比较巧妙的概率型数据结构&#xff08;probabilist…

【gcc】RtpTransportControllerSend学习笔记 3:gcc 算法

本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。本文使用的代码是m79 ,与大神有不同。ChatGPT可以做WebRTC音视频质量性能优化,惊艳到我了 指出了一些QOS学习的方向。大神给出的码率预估…

【排序算法】插入排序

文章目录 一&#xff1a;基本概念1.1 介绍1.2 原理1.3 插入排序法思想 二&#xff1a;代码实现2.1 源码2.2 执行结果2.3 测试八万条数据 三&#xff1a;算法分析3.1 时间复杂度3.2 空间复杂度3.3 稳定性 一&#xff1a;基本概念 1.1 介绍 插入式排序属于内部排序法&#xff0…

【GIT版本控制】--提交更改

一、添加文件到暂存区 在GIT中&#xff0c;要提交更改&#xff0c;首先需要将文件添加到暂存区&#xff08;Staging Area&#xff09;。这是一个用于存放将要提交的更改的临时区域。以下是将文件添加到暂存区的步骤&#xff1a; 打开终端或命令提示符&#xff1a;首先&#x…

基于KubeAdm搭建多节点K8S集群

基于KubeAdm搭建多节点K8S集群 1、基本流程&#xff08;注意 docker 版本和kubeadm、kubelet、kubectl的关系&#xff09;2、安装utils依赖&#xff08;安装范围&#xff1a;主节点工作节点&#xff09;3、安装docker &#xff08;安装范围&#xff1a;主节点工作节点&#xff…

Maven 自动化构建

自动化构建定义了这样一种场景: 在一个项目成功构建完成后&#xff0c;其相关的依赖工程即开始构建&#xff0c;这样可以保证其依赖项目的稳定。 比如一个团队正在开发一个项目 bus-core-api&#xff0c; 并且有其他两个项目 app-web-ui 和 app-desktop-ui 依赖于这个项目。 …

kafka怎么实现零拷贝(Zero-Copy)的?

Kafka 实现零拷贝&#xff08;Zero-Copy&#xff09;主要依赖于操作系统和底层网络库的支持&#xff0c;而不是特定的算法。这是因为零拷贝是一种优化数据传输的技术&#xff0c;通常是通过操作系统和硬件来实现的。以下是 Kafka 如何实现零拷贝的一般原理&#xff1a; 直接内存…

Transformer预测 | Python实现基于Transformer的股票价格预测(tensorflow)

文章目录 效果一览文章概述程序设计参考资料效果一览 文章概述 Transformer预测 | Python实现基于Transformer的股票价格预测(tensorflow) 程序设计 import numpy as np import matplotlib.pyplot

COCI 2021-2022 #1 - Logičari 题解

题目大意 给定一个 n n n 个点的基环树&#xff0c;现在对基环树上的点染色&#xff0c;使得每个点都有且仅有一个与他相连的点&#xff08;不包括它自身&#xff09;被染色&#xff0c;求最少的染色点数&#xff0c;或者返回无解。 思路 先考虑树的情况。 容易想到 DP&am…

README文档模板

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

TCP和UDP的由浅到深的详细讲解

目录 前言 一.TCP 1.1 什么是TCP&#xff1f; 1.2TCP的连接与释放(确认应答机制&#xff09; 1.2.1三次握手 1.2.2四次挥手 1.3TCP滑动窗口&#xff08;效率机制&#xff09; 1.4流量控制&#xff08;安全机制&#xff09; 1.5拥塞控制&#xff08;安全机制&#xff0…

【力扣1812】判断国际象棋棋盘中一个格子的颜色

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接&#xff1a;判断国际象棋棋盘中一个格子的颜色 给你一个坐标 coordina…

环信web、uniapp、微信小程序SDK报错详解---登录篇

项目场景&#xff1a; 记录对接环信sdk时遇到的一系列问题&#xff0c;总结一下避免大家再次踩坑。这里主要针对于web、uniapp、微信小程序在对接环信sdk时遇到的问题。主要针对报错400、404、401、40 (一) 登录用户报400 原因分析&#xff1a; 从console控制台输出及networ…

【C++】哈希与布隆过滤器

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

Unity 之 EditorGUILayout.BeginHorizontal/EndHorizontal异常报错问题

报错内容&#xff1a; 缘由&#xff1a;由于在EditorGUILayout.EndHorizontal()之前执行了类似打开窗口的逻辑 解决办法&#xff1a; 在EditorGUILayout.EndHorizontal()之前执行GUIUtility.ExitGUI();