首页未分类 › linux下宽字符串与多字节字符串之间的转换

linux下宽字符串与多字节字符串之间的转换

最近写linux下的字幕下载软件时,遇到了中文宽字串和多字节串之间的转换问题,这问题困扰了我不久呀,现在终于开窍了。。。
我们知道(请看《Unicode、UTF-8、多字节字符、宽字符》):多字节字符串”你好\n”在源文件以及目标文件中,都是utf-8编码,一个英文字符1字节,一个汉字3字节。因为strlen是根据一字节一字符来计算字符个数的,所以strlen无法处理多字节字符串。
宽字符L”你好\n”在源文件中是utf-8编码,但在目标文件中是UCS编码的,一个字符占4字节。wstrlen便是依据每4字节为一字符,计算有多少字符。

下面看看linux下宽字符串与多字节字符串之间的转换。
首先,Charconvert.c里包含多字节与宽字节字符串的转换函数。

下面是main函数,定义了宽字串wstr和多字节串mstr。并将wstr转换为多字节串mstr2,将mstr转换为wstr2。另外,我把setlocale一句注释了

编译:gcc main.c Charconvert.c -g
运行结果:
sizeof(wchar_t):4
len of wstr:23
len of mstr:31
wstr2:/home/zhao/
mstr2:/home/zhao/
程序输出结果就是/home/zhao/,中文以后的内容就被截断了,这是什么情况呢

我们用gdb来查看下wstr:
x/16b wstr
0×602010: 47 0 0 0 104 0 0 0
0×602018: 111 0 0 0 109 0 0 0

这里只列出了16字节,其实wstr总共是4*23字节这些数字是10进制的。
其中每32位就是一个字符的UCS码,比如47表示‘/’,数值上跟acsii码相等,占4字节;104表示‘h’,数值上也跟acsii码相等,占4字节

再看下mstr:
x/32b mstr
0×400998: 47 104 111 109 101 47 122 104
0x4009a0: 97 111 47 -23 -83 -108 -27 -94
0x4009a8: -125 -28 -69 -103 -24 -72 -86 46
0x4009b0: 99 104 110 46 115 114 116 0

str刚好总共32字节,这里的十进制数是UTF-8编码,47表示‘/’,占1字节;104表示‘h’,占1字节;-23 -83 -108表示‘魔’,占3字节。

看看mstr2:
x/32b mstr2
0x6020a0: 47 104 111 109 101 47 122 104
0x6020a8: 97 111 47 0 0 0 0 0
0x6020b0: 0 0 0 0 0 0 0 0
0x6020b8: 0 0 0 0 0 0 0 0

从‘魔’字开始的字节都变成零了。wstr2内存里也是这样。所以程序输出结果就是/home/zhao/,中文以后的内容就被截断了。

现在我们把setlocale(LC_ALL,””)这句的注释符号去掉。再编译运行看看:
sizeof(wchar_t):4
len of wstr:23
len of mstr:31
wstr2:/home/zhao/魔境仙踪.chn.srt
mstr2:/home/zhao/魔境仙踪.

呵呵,”mstr2:/home/zhao/魔境仙踪.”少了一截,这又是什么情况呢?
显然是WideChar2MultiByte中长度出问题了。。。

发表评论