背景:
linux下的C可执行程序从数据库oracle里读取中文,并将数据通过报文方式送出。
参考:http://www.ibm.com/developerworks/cn/linux/i18n/unicode/linuni/
明确问题:
1)可执行程序本身生成汉字,并进行传送时,字符的编码格式从何处决定?
2)可执行程序本身不生成汉字, 只是从别处取汉字(如从数据库),此时取汉字所进行的编码格式?
--------------------------------------------------------------------------------------------
根据问题1:
由下面的一段话可以看出,可执行程序如是本身生成汉字, 其编码方式会受以下环境变量影响。 (实验证明,此观点有误,详细可以查看后面实例,具体什么原因不清楚。汉字展示生环境变理有关,但生成编码与环境变理无关)
在Linux中通过locale来设置程序运行的不同语言环境,locale由ANSI C提供支持。locale的命名规则为<语言>_<地区>.<字符集编码>,如zh_CN.UTF-8,zh代表中文,CN代表大陆地区,UTF-8表示字符集。在locale环境中,有一组变量,代表国际化环境中的不同设置:
1. LC_COLLATE
定义该环境的排序和比较规则
2. LC_CTYPE
用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等。是最重要的一个环境变量。
3. LC_MONETARY
货币格式
4. LC_NUMERIC
非货币的数字显示格式
5. LC_TIME
时间和日期格式
6. LC_MESSAGES
提示信息的语言。另外还有一个LANGUAGE参数,它与LC_MESSAGES相似,但如果该参数一旦设置,则LC_MESSAGES参数就会失效。LANGUAGE参数可同时设置多种语言信息,如LANGUANE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"。
7. LANG
LC_*的默认值,是最低级别的设置,如果LC_*没有设置,则使用该值。类似于 LC_ALL。
8. LC_ALL
它是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
根据问题2:
由下面的说明,可以得到此处取数据时是有对数据进行字符集转换操作。
NLS_LANG 字符集反映的是客户端操作系统的字符集设置。所以,正确设置 NLS_LANG 可以允许从客户端操作系统字符集到数据库字符集的正确转换。当两端使用同样的字符集设置时, Oracle 会认为数据的发送或接收使用相同的字符集,从而不会发生字符集校验或转换。如果客户端字符集与数据库字符集不一致将会导致乱码,此时转换是有必要的。
---------------------------------------------------------------------------------------------
结论:
1:当程序本身不生产汉字时, 只进行获取时, 由获取处决定编码格式。
说明: GBK 二字节表示一个汉字,UTF-8 三字节表示一个汉字。
待编码汉字:卡友支付-武汉长江航证电子商务有一有限公
GBK
卡BFA8友D3D1支D6A7付B8B6武CEE4汉BABA长B3A4江BDAD航BABD证D6A4电B5E7子D7D3商C9CC务CEF1有D3D0一D2BB有D3D0限CFDE公B9AB
UTF-8
卡%E5%8D%A1友%E5%8F%8B支%E6%94%AF付%E4%BB%98武%E6%AD%A6汉%E6%B1%89长%E9%95%BF江%E6%B1%9F航%E8%88%AA证%E8%AF%81电%E7%94%B5子%E5%AD%90商%E5%95%86务%E5%8A%A1有%E6%9C%89一%E4%B8%80有%E6%9C%89限%E9%99%90公
当对方系统你需以某种字符编码进行数据传送时,需要明确:
1:本程序的字符编码的生成编码(而不是终端查看的情形,可以打出字符的内码进行分析)
2:应用iconv函数族编程实现字符集编码转换。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
实例说明
实例1:汉字字符集内码生成是否与环境变量有关? 结果无关。
实例2:汉字字符集内友生成是否与源文件编码格式有关?结查有关。
--------------------------------------------------------------------------------------------------------
实例1:(GBK纺码)
/*****************************************************************************
* 文件 名:checkiconv.c
* 版 本: 1.00
* 运行环境: linux.
* 功 能:
* 历史记录: 日 期 作 者 备 注
*----------------------------------------------------------------------------*
* 2014-6-30 mengfh 创建.
*
*----------------------------------------------------------------------------*
* All rights reserved. Copyright (C) 2014-2020.
******************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <iconv.h>
//作用,同时进行定义数组的大小,同时做为编码转换出时字节长度
#define OUTLEN 255
int main()
{
// char *in_utf8 = "姝e?ㄥ??瑁?";
// char *in_gb2312 = "正在安装";
//测试数据 ,可以通过工具查看相关的汉字的字符编码http://bm.kdd.cc/index.asp
//UTF-8 友支:%E5%8D%A1友%E5%8F%8B支
//GBK 友支:BFA8友D3D1支
char *in_utf8 = "\xe5\x8d\xa1\xe5\x8f\x8b";
char *in_gb2312 = "\xbf\xa8\xd3\xd1";
char out[OUTLEN];
char tmp[OUTLEN];
int rc=0;
int i=0;
//unicode码转为gb2312码
rc = u2g(in_utf8, strlen(in_utf8), out, OUTLEN);
printf("unicode-->gb2312 out=%s\n", out);
//gb2312码转为unicode码
rc = g2u(in_gb2312, strlen(in_gb2312), out, OUTLEN);
printf("gb2312-->unicode out=%s\n", out);
fprintf(stderr, "此时的out为乱码,请看下面十六进制输出数据:\n");
for(i = 0 ;i <OUTLEN ; i ++)
{
if( out[i]== '\0')
{
fprintf(stderr, "\n");
break;
}
fprintf(stderr," %02X", out[i]);
}
//again
memset(tmp, 0 ,sizeof(tmp));
memcpy(tmp, out, OUTLEN);
rc = u2g(tmp, strlen(tmp), out, OUTLEN);
printf("Again !\nunicode-->gb2312 out=%s\n", out);
return 0 ;
}
//代码转换:从一种编码转为另一种编码
int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset, from_charset);
if (cd == 0)
return -1;
memset(outbuf, 0, outlen);
if (iconv(cd, pin, &inlen, pout, &outlen) == -1)
return -1;
iconv_close(cd);
return 0;
}
//UNICODE码转为GB2312码
int u2g(char *inbuf, int inlen, char *outbuf, int outlen)
{
return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen);
}
//GB2312码转为UNICODE码
int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen)
{
return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);
}
测试环境(UTF-8) :
localhost@/home/term/mengfh/checkfun>>locale
LANG=en_US.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=zh_CN.UTF-8
远程客户端的字符编码也需要调成UTF-8 ——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
unicode-->gb2312 out=¿¨ԑ
gb2312-->unicode out=卡友 (完美的打出)
´̊±µïutΪÒ룬ȫ¿´ЂĦʮ¹½狤³뽾ݣº
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=¿¨ԑ
远程客户端的字符编码也需要调成GBK——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
localhost@/home/term>>locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.ZHS16GBK
LC_CTYPE="en_US.ZHS16GBK"
LC_NUMERIC="en_US.ZHS16GBK"
LC_TIME="en_US.ZHS16GBK"
LC_COLLATE="en_US.ZHS16GBK"
LC_MONETARY="en_US.ZHS16GBK"
LC_MESSAGES="en_US.ZHS16GBK"
LC_PAPER="en_US.ZHS16GBK"
LC_NAME="en_US.ZHS16GBK"
LC_ADDRESS="en_US.ZHS16GBK"
LC_TELEPHONE="en_US.ZHS16GBK"
LC_MEASUREMENT="en_US.ZHS16GBK"
LC_IDENTIFICATION="en_US.ZHS16GBK"
LC_ALL=
远程客户端的字符编码也需要调成GBK——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
远程客户端的字符编码也需要调成UTF-8 ——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=¿¨ԑ
gb2312-->unicode out=卡友
´̊±µïutΪÒ룬ȫ¿´ЂĦʮ¹½狤³뽾ݣº
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=¿¨ԑ
得出结论:
程序自己生产汉字时:字符编码与环境变量没有关系,只关系到显示。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
实例2:
/*****************************************************************************
* 文件 名:checkiconv.c
* 版 本: 1.00
* 运行环境: linux.
* 功 能:
* 历史记录: 日 期 作 者 备 注
*----------------------------------------------------------------------------*
* 2014-6-30 mengfh 创建.
*
*----------------------------------------------------------------------------*
* All rights reserved. Copyright (C) 2014-2020.
******************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <iconv.h>
//作用,同时进行定义数组的大小,同时做为编码转换出时字节长度
#define OUTLEN 255
int main()
{
// char *in_utf8 = "姝e?ㄥ??瑁?";
// char *in_gb2312 = "正在安装";
//测试数据 ,可以通过工具查看相关的汉字的字符编码http://bm.kdd.cc/index.asp
//UTF-8 友支:%E5%8D%A1卡%E5%8F%8B友
//GBK 友支:BFA8卡D3D1友
char *str="卡友";
char *in_utf8 = "\xe5\x8d\xa1\xe5\x8f\x8b";
char *in_gb2312 = "\xbf\xa8\xd3\xd1";
char out[OUTLEN];
char tmp[OUTLEN];
int rc=0;
int i=0;
memset(tmp, 0 ,sizeof(tmp));
memcpy(tmp, str, strlen(str));
for(i = 0 ;i <OUTLEN ; i ++)
{
if( tmp[i]== '\0')
{
fprintf(stderr, "\n");
break;
}
fprintf(stderr," [%d]%02X",i, tmp[i]);
}
//unicode码转为gb2312码
rc = u2g(in_utf8, strlen(in_utf8), out, OUTLEN);
printf("unicode-->gb2312 out=%s\n", out);
//gb2312码转为unicode码
rc = g2u(in_gb2312, strlen(in_gb2312), out, OUTLEN);
printf("gb2312-->unicode out=%s\n", out);
fprintf(stderr, "文件以GBK进行编码此时的out为乱码,请看下面十六进制输出数据:\n");
for(i = 0 ;i <OUTLEN ; i ++)
{
if( out[i]== '\0')
{
fprintf(stderr, "\n");
break;
}
fprintf(stderr," %02X", out[i]);
}
//again
memset(tmp, 0 ,sizeof(tmp));
memcpy(tmp, out, OUTLEN);
rc = u2g(tmp, strlen(tmp), out, OUTLEN);
printf("Again !\nunicode-->gb2312 out=%s\n", out);
return 0 ;
}
//代码转换:从一种编码转为另一种编码
int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset, from_charset);
if (cd == 0)
return -1;
memset(outbuf, 0, outlen);
if (iconv(cd, pin, &inlen, pout, &outlen) == -1)
return -1;
iconv_close(cd);
return 0;
}
//UNICODE码转为GB2312码
int u2g(char *inbuf, int inlen, char *outbuf, int outlen)
{
return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen);
}
//GB2312码转为UNICODE码
int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen)
{
return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);
}
LANG=en_US.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=zh_CN.UTF-8
源代码以GBK进行编码时:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
源代码以utf-8进行编码时:
localhost@/home/term/mengfh/checkfun>>./checkiconv2
[0]FFFFFFE5 [1]FFFFFF8D [2]FFFFFFA1 [3]FFFFFFE5 [4]FFFFFF8F [5]FFFFFF8B
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
?.欢浠?TF-8杩.?缂..姝ゆ.?.ut涓轰贡?.?璇风.涓..?..杩..杈..?版.锛
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
====》结论,C程序自身产生的字符编码(即内码)与源文件以何种方式进行编程有关。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
以下是摘抄网上iconv的实现部分:
http://blog.youkuaiyun.com/yukin_xue/article/details/7652154
-----------------------------------------------------------------------------------------------------------------
一、利用iconv函数族进行编码转换
iconv函数族的头文
在LINUX上进行编码转换时,既可以利用iconv函数族编程实现,也可以利用iconv命令来实现,只不过后者是针对文件的,即将指定文件从一种编码转换为另一种编码。
一、利用iconv函数族进行编码转换
iconv函数族的头文件是iconv.h,使用前需包含之。
#include <iconv.h>
iconv函数族有三个函数,原型如下:
(1) iconv_t iconv_open(const char *tocode, const char *fromcode);
此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。 (3) int iconv_close(iconv_t cd);
此函数用于关闭转换句柄,释放资源。
相关实例:
例子1: 用C语言实现的转换示例程序/* f.c : 代码转换示例C程序 */
#include <iconv.h>
#define OUTLEN 255
main()
{
char *in_utf8 = "姝e?ㄥ??瑁?";
char *in_gb2312 = "正在安装";
char out[OUTLEN];
//unicode码转为gb2312码
rc = u2g(in_utf8,strlen(in_utf8),out,OUTLEN);
printf("unicode-->gb2312 out=%sn",out);
//gb2312码转为unicode码
rc = g2u(in_gb2312,strlen(in_gb2312),out,OUTLEN);
printf("gb2312-->unicode out=%sn",out);
}
//代码转换:从一种编码转为另一种编码
int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1) return -1;
iconv_close(cd);
return 0;
}
//UNICODE码转为GB2312码
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB2312码转为UNICODE码
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}
例子2: 用C++语言实现的转换示例程序
/* f.cpp : 代码转换示例C++程序 */
#include <iconv.h>
#include <iostream>
#define OUTLEN 255
using namespace std;
// 代码转换操作类
class CodeConverter {
private:
iconv_t cd;
public:
// 构造
CodeConverter(const char *from_charset,const char *to_charset) {
cd = iconv_open(to_charset,from_charset);
}
// 析构
~CodeConverter() {
iconv_close(cd);
}
// 转换输出
int convert(char *inbuf,int inlen,char *outbuf,int outlen) {
char **pin = &inbuf;
char **pout = &outbuf;
memset(outbuf,0,outlen);
return iconv(cd,pin,(size_t *)&inlen,pout,(size_t *)&outlen);
}
};
int main(int argc, char **argv)
{
char *in_utf8 = "姝e?ㄥ??瑁?";
char *in_gb2312 = "正在安装";
char out[OUTLEN];
// utf-8-->gb2312
CodeConverter cc = CodeConverter("utf-8","gb2312");
cc.convert(in_utf8,strlen(in_utf8),out,OUTLEN);
cout << "utf-8-->gb2312 in=" << in_utf8 << ",out=" << out << endl;
// gb2312-->utf-8
CodeConverter cc2 = CodeConverter("gb2312","utf-8");
cc2.convert(in_gb2312,strlen(in_gb2312),out,OUTLEN);
cout << "gb2312-->utf-8 in=" << in_gb2312 << ",out=" << out << endl;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OUTLEN 255
main()
{
char *in_utf8 = "utf8字符串";
char *in_gb2312 = "\xbe\xb2\xcc\xac\xc4\xa3\xca\xbd";
char out[OUTLEN];
int rec ;
//unicode码转为gb2312码
rec = u2g(in_utf8,strlen(in_utf8),out,OUTLEN);
printf("unicode-->gb2312 out=%s\n",out);
//gb2312码转为unicode码
rec = g2u(in_gb2312,strlen(in_gb2312),out,OUTLEN);
printf("gb2312-->unicode out=%s \n",out);
}
//代码转换:从一种编码转为另一种编码
int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1) return -1;
iconv_close(cd);
return 0;
}
//UNICODE码转为GB2312码
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB2312码转为UNICODE码
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}