Windows 程序支持 Unicode
宽字符
阅读了 UTF-8 Everywhere 一文,推荐在程序中对于字符串都使用 UTF-8 编码。Unix-like 系统默认是支持 UTF-8 编码的Unicode字符串,标准库函数也默认支持 UTF-8 字符串,如 fopen 等。但在 Windows 系统,由于历史原因,其对需要输入宽字符的函数提供了另外以 w 开头的标准库扩展函数,如 _wfopen 等。况且对标准库的 wchar_t 两种系统实现不一样,在 unix-like 系统中是占4字节的 UTF-8 编码,而在 Windows 系统中是占2字节的 UTF-16 编码。Windows 很多系统 API 接受 wchar_t 类型的字符串,这就需要把 UTF-8 编码的字符串转换为 UTF-16。
编码转换
UTF-8 Everywhere 文中提供了一个解决方案,在程序中的字符串统一使用 UTF-8 编码并使用 char 或 string 存储而不使用宽字符类型。在需要传入宽字符类型时进行转换,实现 widen 和 narrow 两种类型的函数,完成 UTF-8 和 UTF-16 的互相转换。
std::string narrow(const wchar_t *s);
std::wstring widen(const char *s);
std::string narrow(const std::wstring &s);
std::wstring widen(const std::string &s);
wchar_t *widen(const char *s);
char *narrow(const wchar_t *s);
在调用需要传入宽字符串的 Windows API时,使用 widen 函数转换字符串。
CopyFileW(widen(existing_file).c_str(),
widen(new_file).c_str(),
TRUE);
函数实现
在 Boost.Nowide 中,包含 widen 和 narrow 两种类型函数的实现,并对标准库函数进行了包装,使得可以编写跨平台支持 Unicode 的程序。
UTF-8 Everywhere 中也提到可以使用 Windows 的 MultiByteToWideChar 和 WideCharToMultiByte 两个 API 实现两个转换函数。
#include <windows.h>
wchar_t *widen(const char *s, wchar_t *ws, size_t ws_size) {
size_t required_size;
// Get the required buffer size
required_size = MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, 0);
if (required_size >= ws_size)
return NULL;
// Convert NULL terminated UTF-8 string to the UTF-16 (wide character) string
if (MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws_size) == 0)
return NULL;
return ws;
}
char *narrow(const wchar_t *ws, char *s, size_t s_size) {
size_t required_size;
// Get the required buffer size
required_size = WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, 0, NULL, NULL);
if (required_size >= s_size)
return NULL;
// Convert NULL terminated UTF-8 string to the UTF-16 (wide character) string
if (WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, s_size, NULL, NULL) == 0)
return NULL;
return s;
}
写代码测试两个函数时,遇到了控制台输出乱码问题。UTF-8 字符串转换为 wchar_t 类型字符串之后应该就能使用 wprintf 函数输出,但实际只有英文字符能正常输出,中文就是乱码。这主要时因为控制台使用的编码方式不是 Unicode, 中文的系统默认是 GBK,而宽字符输出的是 UTF-16,这中间就存在编码转换的问题,库函数 wprintf 没有自动转换。查看 Boost.Nowide 对 Console I/O 的实现说明,其利用的是 ReadConsoleW/WriteConsoleW 系统 API。WriteConsoleW 支持输出 Unicode 字符串,改用该函数控制台正确显示中文字符。
void print_wstring(const wchar_t *ws) {
DWORD w;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), ws, wcslen(ws), &w, NULL);
}
int main(void) {
char cc[] = "\xE4\xB8\x80y\n";
wchar_t utf16[512];
wchar_t uu[] = L"一\n";
print_wstring(widen(cc, utf16, sizeof(utf16)));
print_wstring(uu);
system("pause");
return 0;
}

源代码中的 UTF-8 字符串非 ASCII 字符直接使用16进制表示,wchar_t 类型的可以直接输入,但源代码文件使用的编码方式要支持Unicode 编码。编译器会自动根据源代码文件的编码方式解码字符串并使用 wchar_t 类型的编码方式编码字符串存储在最终编译生成的可执行文件中,在 Windows 系统中就是 UTF-16。为了避免不必要的编码问题,源代码文件也统一使用 UTF-8 编码保存,不过 visual studio 要使用带 BOM 的 UTF-8,不带 BOM 的不能正确识别。vs 2010 中打开 File -> Adavanced Save Options进行设置。
Windows 程序支持 Unicode的更多相关文章
- windows控制台程序——关于UNICODE字符的总结(转)
前言:从Windows NT/2000开如,Windows系统已经是一个标准的UNICODE系统,系统内部所有字符串存储及操作均使用UNICODE编码.因此Win32 API都是UNICODE版本的, ...
- C++不支持Unicode,即使utf8
今天,字符串unicode我们已经不需要常理的理由,但是,一些有编程语言的悠久历史.这仍然是一个头疼. 尽管第三方库支持的假设,C++事实上没有真正有效地支持unicode.即使utf8.(注意:本文 ...
- Windows程序员必须知道的字符编码和字符集
字符编码 (Character encoding) 在存储和传递文本过程中,为了使得所有电脑都能够正确的识别出文本内容,需要有一个统一的规则. 2. 字符集 (Character Set) ) 一般 ...
- VC6.0支持UNICODE的步骤
针对MFC程序的开发,支持Unicode一共需要三步: Step1 设置->C/C++预处理定义中,删除_MBCS,添加_UNICODE,UNICODE. Step2 设置->Link-& ...
- 使你的C/C++代码支持Unicode(CRT字符串处理的所有API列表,甚至有WEOF字符存在)
悉Microsoft支持Unicode的方式. 它的主要目的是方便你查询相关的数据类型和函数,以及修正相应的拼写错误. I18nGuy 主页 XenCraft (Unicode 咨询公司) Engli ...
- windows程序设计基础知识
Win32 API(Application Programming Interface) Win32 API可认为是一个程序库,提供各式各样的与windows系统服务有关的函数. Win32 API是 ...
- Windows编程中UNICODE和_UNICODE定义问题
Windows编程中UNICODE和_UNICODE定义问题 先转一篇文章: 初学Windows SDK编程时碰到过这个问题,相信很多初学Windows编程的人也都碰到过,后来慢慢搞明白些了,但有时别 ...
- Linux下运行windows程序
现在Winxp停止了支持,那我们的windows程序是否可以再linux上执行呢,如下是一些参考的信息 在您的 Linux/Mac 操作系统上运行 Windows 软件 http://www.wine ...
- Windows程序----初识Windows程序
先来看一些励志名言来激励一下自己吧! 励志名言:每一发奋发奋的背后,必有加倍的赏赐 1.有无目标是成功者与平庸者的根本差别. 2.成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成. 3.当 ...
随机推荐
- MIM协议与Base64编码
MIME Protocol 1. MIME的全称是"Multipurpose Internet Mail Extensions",中译为"多用途互联网邮件扩展" ...
- C语言or和and运算
#include <stdio.h> void main () { printf( | ); printf( | ); printf( | ); printf( | ); printf( ...
- 基于无锁的C#并发队列实现(转载)
最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共 ...
- mybatis 使用resultMap实现数据库的操作
resultType:直接表示返回类型 resultMap:对外部resultMap的引用 二者不能同时使用 创建一个实体类Role和User public class Role { private ...
- 网站的PV,UV,IP名词解释
PV:PV 是Page Views的缩写,即页面浏览量,用户每一次对网站中的每个网页访问均被记录一次.注意,访客每刷新一次页面,pv就增加一次. UV:UV是Unique Visitor的缩写,即独立 ...
- C语言中strstr函数
头文件:#include <string.h> strstr()函数用来检索子串在字符串中首次出现的位置,其原型为: char *strstr( char *str, char * ...
- poj1012.Joseph(数学推论)
Joseph Time Limit: 1 Sec Memory Limit: 64 MB Submit: 493 Solved: 311 Description The Joseph's prob ...
- cocos基础教程(4)基础概念介绍
在Cocos2d-x-3.x引擎中,采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景,一个场景又可以分为不同的层,一个层又可以拥有任意个可见的游戏节点(即对象,游戏中基本上所有的类都派生于 ...
- [Effective JavaScript 笔记]第35条:使用闭包存储私有数据
js的对象系统并没有特别鼓励或强制信息隐藏.所有的属性名都是一个字符串,任意一个程序都可以简单地通过访问属性名来获取相应的对象属性.例如,for...in循环.ES5的Object.keys()和Ob ...
- MBProgressHUD使用
//方式1.直接在View上show HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain]; HUD.delegat ...