實用為主,相關知識背景另行查閱
編碼場景
這里涉及的編碼分為兩個場景:源碼文件的編碼格式和源碼中字符在目標文件中的編碼。
源碼文件的編碼格式
- -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\n", 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\n"); 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
是不是很方便,后面有時間再研究下如何自己編譯這些動態鏈接庫。。。