文号
t79792
阅读
5295
回复
3
收藏
1
VC++常用转码库
2016/05/01
IP:四川
Visual C++编写控制台程序是ANSI编码的,然而这种编码比较过时,因此编程时常与其它两种字符串打交道:
一种是宽字符,一般WinAPI、COM、.NET使用这种字符串;
一种是UTF-8,一般来自网络数据。

这几种编码之间的转换一般使用MultiByteToWideChar和WideCharToMultiByte函数。
但是这个函数使用比较麻烦,特别是UTF-8,需要分配缓冲区,转码两次,再释放掉缓冲区。

提供的常用转码函数:
to_wide ANSI转换为宽字符
from_wide 宽字符转换为ANSI
to_utf8 ANSI转换为UTF-8
from_utf8 UTF-8转换为ANSI
utf8_to_wide UTF-8转换为宽字符
utf8_from_wide 宽字符转换为UTF-8

以上函数的参数列表基本相同(均为3个),使用方法(以to_utf8为例):
int retval = to_utf8(NULL, 0, srcstr); // 返回所需缓冲区大小(以字符计)
int retval = to_utf8(outbuf, outbufsize, srcstr); // 成功返回已写入大小(以字符计),失败返回0

另有一个使用堆内存保存结果的to_utf8_alloc函数,使用方法如下:
char *result = to_utf8_alloc(srcstr);
free(result);
由于from_utf8可以安全地执行就地转换(ANSI永远比UTF-8小),没有必要提供from_utf8_alloc函数。
如果需要这个功能的话,可以使用接下来要讲到的cp_to_cp_alloc实现。

以上常用转码函数是由以下六个通用转码函数封装得到的:
cp_to_wide 指定代码页转换为宽字符
cp_from_wide 宽字符转换为指定代码页
cp_to_wide_alloc 指定代码页转换为宽字符并返回包含结果的堆内存指针
cp_from_wide_alloc 宽字符转换为指定代码页并返回包含结果的堆内存指针
cp_to_cp 转换代码页
cp_to_cp_alloc 转换代码页并返回包含结果的堆内存指针

使用示例如下所示(使用了MessageBoxW显示宽字符串,因此需要#include <windows.h>):
#pragma comment(lib, "user32.lib") // MessageBoxW
                 
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> // MessageBoxW
#include "../zm.h"
                 
int main()
{
    char ansi_str[] = "我是中文示例12345678";
    wchar_t wide_str[] = L"我是\u315D\u314F\uB204\uB77C12345678";
    char utf8_a[256] = "";
    char utf8_b[256] = "";
    char ansi_a[256] = "";
    char ansi_b[256] = "";
    char ansi_c[256] = "";
    wchar_t wide_a[256] = L"";
    wchar_t wide_b[256] = L"";
                 
    printf("ansi_str=%s\n", ansi_str); // 显示原始ANSI字符串
    printf("wide_str=[see MessageBox]\n");
    MessageBoxW(NULL, wide_str, L"wide_str", MB_OK); // 显示原始宽字符串
                     
    to_utf8(utf8_a, 256, ansi_str); // ANSI转码到UTF-8
    printf("utf8_a=%s [from ansi_str]\n", utf8_a);
                 
    char *utf8_alloc = to_utf8_alloc(ansi_str); // ANSI使用堆内存转码到UTF-8
    printf("utf8_alloc=%s [from ansi_str]\n", utf8_alloc);
    free(utf8_alloc);
                 
    utf8_from_wide(utf8_b, 256, wide_str); // 宽字符转码到UTF-8
    printf("utf8_b=%s [from wide_str]\n", utf8_b);
                 
    from_wide(ansi_a, 256, wide_str); // 宽字符转码到ANSI
    printf("ansi_a=%s [from wide_str]\n", ansi_a);
                  
    from_utf8(ansi_b, 256, utf8_a); // UTF-8转码到ANSI(1)
    printf("ansi_b=%s [from utf8_a]\n", ansi_b);
                 
    from_utf8(ansi_c, 256, utf8_b); // UTF-8转码到ANSI(2)
    printf("ansi_c=%s [from utf8_b]\n", ansi_c);
                 
    to_wide(wide_a, 256, ansi_str); // ANSI转码到宽字符
    printf("wide_a=[see MessageBox] [from ansi_str]\n");
    MessageBoxW(NULL, wide_a, L"wide_a [from ansi_str]", MB_OK);
                 
    utf8_to_wide(wide_b, 256, utf8_b); // UTF-8转码到宽字符
    printf("wide_b=[see MessageBox] [from utf8_b]\n");
    MessageBoxW(NULL, wide_b, L"wide_b [from utf8_b]", MB_OK);
                 
    return 0;
}</windows.h></stdlib.h></stdio.h>

运行结果:

Capture.png
[ 修改于10年3个月前 - 2016/09/02 18:48:47 ]
acmilan作者
10年7个月前修改于 10年7个月前IP:四川
818007
1楼
注意to_utf8, from_utf8, cp_to_cp三个函数,使用这些函数,如果先获取缓冲区大小,再分配缓冲区,再执行转换,内部会重复分配、转换、释放两次,这样效率可能比较低。
对于常用的from_utf8(UTF-8转ANSI),目标字符串(ANSI)不可能比源字符串(UTF-8)长,可以执行就地转换。
对于其它情况,如果需要使用堆内存放置结果,则应使用to_utf8_alloc或cp_to_cp_alloc函数,以避免重复分配和释放内存。
引用
评论
acmilan作者
10年7个月前修改于 10年7个月前IP:四川
818017
2楼
。。。现在主要精力放在.NET上面,因此此程序不再维护,如果有什么问题请自己修改
引用
评论
acmilan作者
10年7个月前修改于 10年3个月前IP:四川
818032
3楼
。。。。。。
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的