实用为主,相关知识背景另行查阅
编码场景
这里涉及的编码分为两个场景:源码文件的编码格式和源码中字符在目标文件中的编码。
源码文件的编码格式
- -finput-charset
该选项指源码文件的编码,如GBK,UTF-8,当然,你的host得支持。GCC调用host的字符转换功能将源文件的
编码格式转换为GCC内部编码格式UTF-8,然后再进行处理。
字符在目标文件中的编码
这个问题可以理解为你在源码中定义的字符串在内存中(当然是先编译进目标文件的)是如何被表示的。又要分
为两类:窄字符和宽字符。
- -fexec-charset
即常用的 char 类型字符,每个字符占用1个字节,例如:
char str = "字符串";
- -fwide-exec-charset
即 wchar_t 类型字符,每个字符占用4个字节,例如:
wchar_t wstr = L"字符串"
单独的编码转换
函数
如果你的源码中有多个字符串需要使用不同的编码,那么 -fexec-charset 和 -fwide-exec-charset 也就没有办法了。libc提供了
编码转换函数iconv,其实是一组函数,头文件:"iconv.h",函数原型如下:
1 /* Allocate descriptor for code conversion from codeset FROMCODE to 2 codeset TOCODE. 3 4 This function is a possible cancellation point and therefore not 5 marked with __THROW. */ 6 extern iconv_t iconv_open (const char *__tocode, const char *__fromcode); 7 8 /* Convert at most *INBYTESLEFT bytes from *INBUF according to the 9 code conversion algorithm specified by CD and place up to 10 *OUTBYTESLEFT bytes in buffer at *OUTBUF. */ 11 extern size_t iconv (iconv_t __cd, char **__restrict __inbuf, 12 size_t *__restrict __inbytesleft, 13 char **__restrict __outbuf, 14 size_t *__restrict __outbytesleft); 15 16 /* Free resources allocated for descriptor CD for code conversion. 17 18 This function is a possible cancellation point and therefore not 19 marked with __THROW. */ 20 extern int iconv_close (iconv_t __cd);
为了使用方便,封装成了一个函数,也可以看作是使用方法的演示:
1 int charset_conv( char *from_charset, 2 char *to_charset, 3 char *inbuf, 4 size_t inlen, 5 char *outbuf, 6 size_t outlen 7 ) 8 { 9 iconv_t cd; 10 char **pin = &inbuf; 11 char **pout = &outbuf; 12 size_t n; 13 14 cd = iconv_open(to_charset,from_charset); 15 if (cd == (iconv_t)-1) { 16 if (errno == EINVAL) { 17 printf("iconv_open: form %s to %s not support ", from_charset, to_charset); 18 } 19 20 return -1; 21 } 22 23 memset(outbuf,0,outlen); 24 25 n = iconv(cd, pin, &inlen, pout, &outlen); 26 if (n == (size_t)-1) { 27 printu(LOG_DEBUG, "iconv: error "); 28 } 29 30 iconv_close(cd); 31 32 return n; 33 }
如果想将UTF-16编码的字符串转换为GBK编码的字符串,可以这样使用:
1 charset_conv("UTF-16", "GBK", p_in, size_in, p_out, size_out);
iconv相关文件
在PC机上使用iconv一般都会正常,但是一旦到了嵌入式linux中,往往会调用失败,这是因为缺少相关文件。libc只实现了接口iconv,
但并没有实现具体的转换细节,可以想想,那么多的编码类型,如果都集成到libc库中,该是多么庞大!实际上转换细节使用动态链接库实现的。
文件位于:
/usr/lib/gconv
再看具体文件:
gconv-modules:指出了做相应转换应该调用的文件
*.so:实现由内部编码到某种编码转换的动态链接库
所以,为了支持UTF-16到GBK的转换,我们至少需要3个文件:
UTF-16.so
GBK.so
gconv-modules
其中gconv-modules应包含如下内容:
# from to module cost
module GBK// INTERNAL GBK 1
module INTERNAL GBK// GBK 1
# from to module cost
module UTF-16// INTERNAL UTF-16 1
module INTERNAL UTF-16// UTF-16 1
那么这些文件从那里来呢,最方便的就是从编译器目录拷贝,例如CodeSourcery g++ Lite(某厂商提供的ARM GCC),对应默认指令集的库的
路径是:
arm-none-linux-gnueabi/libc/usr/lib/gconv
是不是很方便,后面有时间再研究下如何自己编译这些动态链接库。。。