目录

第1章小心Windows7的UTF-8代码页    1

1.1 UTF-16与UTF-8相互转换    1

1.1.1 使用Windows API    1

1.1.2 自己编码    1

1.2 测试代码    4

1.3 测试结果    5

第1章小心Windows7的UTF-8代码页

1.1 UTF-16与UTF-8相互转换

发现Windows7的UTF-8代码页有问题的根源就在于UTF-16与UTF-8的相互转换。

1.1.1 使用Windows API

使用Windows API,可以实现UTF-16编码与UTF-8编码的相互转换,如下面的代码:

char a1[128];

wchar_t w = 0;

int n1 = 0;

wchar_t w1[128];

int m1 = 0;

n1 = WideCharToMultiByte(CP_UTF8,0,&w,1,a1,128,NULL,NULL);

m1 = MultiByteToWideChar(CP_UTF8,0,a1,n1,w1,128);

WideCharToMultiByte把UTF-16编码转换为UTF-8编码;

MultiByteToWideChar把UTF-8编码转换为UTF-16编码。

API函数WideCharToMultiByte和MultiByteToWideChar能够正常工作的前提是:Windows系统已经安装了UTF-8代码页。Windows XP、Windows 7默认已经安装了UTF-8代码页,因此不用太担心。Windows Mobile系统就有些麻烦了:有些Windows Mobile安装了UTF-8代码页,而有些没有。所以,为了程序在所有Mobile设备上正常运行,是不能使用WideCharToMultiByte和MultiByteToWideChar的。

1.1.2 自己编码

UTF-16与UTF-8的相互转换,不能使用WideCharToMultiByte和MultiByteToWideChar,怎么办?所幸的是:UTF-16与UTF-8的相互转换是有严格的转换关系的。本文不做这方面的论述,直接上VC++代码:

/*******************************************************************\

将 UTF16 字符串转换为 UTF8 字符串

pUTF16 [in] UTF16 字符串首地址

nLen16 [in] UTF16 字符串字符数,小于 0 表示以 \0 结尾

pUTF8 [out] UTF8 字符串首地址,可以为 NULL

返回:转换的 UTF8 字符个数

\*******************************************************************/

long UTF16to8(const wchar_t*pUTF16,long nLen16,char*pUTF8)

{

long nLen8 = 0;

if(pUTF16)

{

if(nLen16 < 0)

{

nLen16 = wcslen(pUTF16) + 1;

}

}

else

{

nLen16 = 0;

}

if(nLen16 > 0)

{

long i = 0;

wchar_t u = 0;

for(i = 0;i < nLen16;++i)

{

u = pUTF16[i];

if(u <= 0x7F)

{

if(pUTF8)

{

*pUTF8++ = (char)u;

}

++nLen8;

}

else if(u <= 0x7FF)

{

if(pUTF8)

{//110xxxxx 10xxxxxx

pUTF8[1] = (char)(u & 0x3F | 0x80); u >>= 6;

pUTF8[0] = (char)(u & 0x1F | 0xC0);

pUTF8 += 2;

}

nLen8 += 2;

}

else

{

if(pUTF8)

{//1110xxxx 10xxxxxx 10xxxxxx

pUTF8[2] = (char)(u & 0x3F | 0x80); u >>= 6;

pUTF8[1] = (char)(u & 0x3F | 0x80); u >>= 6;

pUTF8[0] = (char)(u & 0x0F | 0xE0);

pUTF8 += 3;

}

nLen8 += 3;

}

}

}

return nLen8;

}

/*******************************************************************\

将 UTF8 字符串转换为 UTF16 字符串

pUTF8 [in] UTF8 字符串首地址

nLen8 [in] UTF8 字符串字符数,小于 0 表示以 \0 结尾

pUTF16 [out] UTF16 字符串首地址,可以为 NULL

返回:转换的 UTF16 字符个数

\*******************************************************************/

long UTF8to16(const char*pUTF8,long nLen8,wchar_t*pUTF16)

{

long nLen16 = 0;

if(pUTF8)

{

if(nLen8 < 0)

{

nLen8 = strlen(pUTF8) + 1;

}

}

else

{

nLen8 = 0;

}

if(nLen8 > 0)

{

long i = 0;

unsigned char u = 0;

for(i = 0;i < nLen8;)

{

u = pUTF8[i];

if(u >= 0xE0)

{

if(pUTF16)

{

*pUTF16++ = (pUTF8[i] & 0x0f) << 12

| (pUTF8[i + 1] & 0x3f) << 6

| (pUTF8[i + 2] & 0x3f);

}

i += 3;

}

else if(u >= 0xC0)

{

if(pUTF16)

{

*pUTF16++ = (pUTF8[i] & 0x1f) << 6

| (pUTF8[i + 1] & 0x3f);

}

i += 2;

}

else

{

if(pUTF16)

{

*pUTF16++ = u;

}

++i;

}

++nLen16;

}

}

return nLen16;

}

1.2 测试代码

自己编写的代码在使用前,那是要测试的。下面就是测试代码。其实就是与WideCharToMultiByte和MultiByteToWideChar进行比较:

void Test()

{

char a1[128];

char a2[128];

wchar_t w;

int n1 = 0;

int n2 = 0;

wchar_t w1[128];

wchar_t w2[128];

int m1 = 0;

int m2 = 0;

for(long i = 0;i <= 0xFFFF;++i)

{

w = (wchar_t)i;

n1 = WideCharToMultiByte(CP_UTF8,0,&w,1,a1,128,NULL,NULL);

m1 = MultiByteToWideChar(CP_UTF8,0,a1,n1,w1,128);

if(m1 != 1 && w1[0] != w)

{//WideCharToMultiByte与MultiByteToWideChar相互转换有问题

TRACE(_T("WideCharToMultiByte,MultiByteToWideChar=%04X\n"),w);

}

n2 = UTF16to8(&w,1,a2);

m2 = UTF8to16(a2,n2,w2);

if(m2 != 1 && w2[0] != w)

{//UTF16to8与UTF8to16相互转换有问题

TRACE(_T("UTF16to8,UTF8to16=%04X\n"),w);

}

if(n1 != n2 || memcmp(a1,a2,n1))

{//UTF16to8与WideCharToMultiByte有出入

TRACE(_T("WideCharToMultiByte,UTF16to8=%04X\n"),w);

}

}

}

1.3 测试结果

测试结果是:

1、在Windows XP下一切正常;

2、在Windows 7(64位旗舰版)下出问题了:当w在0xD800~0xD98A之间时,UTF16to8与WideCharToMultiByte的转换结果不一致!

笔者相信自己的代码,同时又有Windows XP的证明,最终得出的结论就是:Windows7的UTF-8代码页有问题!

还好,0xD800~0xD98A的395个字符并不是很常用,否则Windows7保存的UTF-8文件到了Windows XP或Linux下显示出乱码,问题就严重了。

解决方案:UTF-16与UTF-8编码的相互转换,还是自己编码实现吧。

小心Windows7的UTF-8代码页的更多相关文章

  1. CodePage------Encoding 类支持的编码以及与这些编码关联的代码页(CodePage)

    Encoding 类 .NET Framework 4  表示字符编码. 继承层次结构 System.Object  System.Text.Encoding    System.Text.ASCII ...

  2. 刨根究底字符编码之七——ANSI编码与代码页(Code Page)

    ANSI编码与代码页(Code Page) 一.ANSI编码 1. 如前所述,在全世界所有国家和民族的文字符号统一编码的Unicode编码方案问世之前,各个国家.民族为了用计算机记录并显示自己的字符, ...

  3. CMD代码页

    不同字符编码在CMD模式下会出现乱码,需要使用 chcp 代码页 命令来更改代码页显示正常. UTF-8  65001 简体中文 936 437          美国 850          多语 ...

  4. 解决“在多字节的目标代码页中,没有此Unicode字符可以映射到的字符”

    今天在处理Google网站管理员中的500错误时发现这样一些URL: http://www.cnblogs.com/Garnai/tag/3D%3F%96%CA/ http://www.cnblogs ...

  5. Windows代码页、区域

    目录 第1章代码页    1 1 代码页    1 1.1 单字节字符集    1 1.2 双字节字符集    1 1.3 多字节字符集    1 1.4 ANSI代码页    2 2 枚举代码页   ...

  6. 更改cmd代码页,修正语言显示

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 rem 英文 chcp 437   rem 日文 chcp 932   rem 简体中文 chcp 936   re ...

  7. warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失

    bug来源: 一直在看sift然后就手贱的给 opencv源码做注释,如果在vs里面打开会一直相安无事,但是问题出在我用了notepad++. 这样就报了标题的错误. 因为notepad++会以uni ...

  8. Visual Studio在页面按F7不能跳转至cs代码页的解决方法

    检查页面Page设置内的CodeBehind属性,看是否与代码页的文件名相同,不同则改正,问题得以解决.

  9. warning: C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失

    ------问题-------------------- Qt项目使用 VC++ 编译器出现此错误. warning: C4819: 该文件包含不能在当前代码页(936)中表示的字符.请将该文件保存为 ...

随机推荐

  1. Intent传递对象——Serializable和Parcelable区别

    为什么要将对象序列化? 1.永久性保存对象,保存对象的字节序列到本地文件中: 2.用过序列化对象在网络中传递对象: 3.通过序列化对象在进程间传递对象. 1.实现Serializable接口 Seri ...

  2. yum报错

    用man clean all man yum,可以看到,clean选项的作用是: Is  used  to clean up various things which accumulate in th ...

  3. MUI 框架微信支付

    在MUI 框架中实现了支付宝支付后,以为MUI微信支付,也没什么大问题,结果这个问题困扰了我几天,后面再同事的提醒下终于弄出来了, 问题出在,开始使用Dcloud 公有证书 怎么也付不了....,后面 ...

  4. 【MySQL】MySQL复制表结构、表数据

    平常,复制.备份表,一般都直接操作IDE完成.但有时,一些初始化数据的脚本,在操作数据前,最好备份下操作表的结构.数据,不至于出错了被置于为难的境地. 所以复制表结构.表数据的语句就派上用场. > ...

  5. GMT时间转换

    /// <summary> /// GMT时间转成本地时间 /// </summary> /// <param name="gmt">字符串形式 ...

  6. uTenux——LED驱动讲解

    LED驱动讲解,对于一个嵌入式的工程师还是一个刚开是学习相关电子设计的朋友,对于LED的驱动问题应该不甚陌生.我所说的LED驱动并不是类似大功率LED照明的那个驱动,而是简单的控制器对LED的控制驱动 ...

  7. 【leetcode❤python】206. Reverse Linked List

    # Definition for singly-linked list.# class ListNode(object):#     def __init__(self, x):#         s ...

  8. C# 多线程 Invoke BeginInvoke

    Invoke在线程中等待Dispatcher调用指定方法,完成后继续下面的操作. BeginInvoke不必等待Dispatcher调用制定方法,直接继续下面的操作. 来自:百度知道 这个在线程中操作 ...

  9. 【原创】pads2007 Layout 电气连接性检查过孔显示错误

    如图所示的电源铜皮过孔,勾选stiching选项,连接性检查会报错误: 去掉stiching选项,连接错误消失.

  10. Verify an App Store Transaction Receipt 【苹果服务端 验证一个应用程序商店交易收据有效性】

    转自:http://blog.csdn.net/saindy5828/article/details/6414014 1. 从Transaction 的TransactionReceipt属性中得到接 ...