linux下C可执行程序输出字符集编码(内码)分析

背景:

    linux下的C可执行程序从数据库oracle里读取中文,并将数据通过报文方式送出。

参考:http://www.ibm.com/developerworks/cn/linux/i18n/unicode/linuni/

明确问题:

    1)可执行程序本身生成汉字,并进行传送时,字符的编码格式从何处决定?

    2)可执行程序本身不生成汉字, 只是从别处取汉字(如从数据库),此时取汉字所进行的编码格式?

--------------------------------------------------------------------------------------------

根据问题1: 

    由下面的一段话可以看出,可执行程序如是本身生成汉字, 其编码方式会受以下环境变量影响。 (实验证明,此观点有误,详细可以查看后面实例,具体什么原因不清楚。汉字展示生环境变理有关,但生成编码与环境变理无关)

Linux中通过locale来设置程序运行的不同语言环境,localeANSI C提供支持。locale的命名规则为<语言>_<地区>.<字符集编码>,如zh_CN.UTF-8zh代表中文,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);
} 



 



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


源代码以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.csdn.net/yukin_xue/article/details/7652154

-----------------------------------------------------------------------------------------------------------------

在LINUX上进行编码转换时,既可以利用iconv函数族编程实现,也可以利用iconv命令来实现,只不过后者是针对文件的,即将指定文件从一种编码转换为另一种编码。 
   一、利用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; 
   }


 
linux C 字符集转换,UTF-8,GB2312
最近帮朋友写个系统接口的小东东,2个系统字符集不同,一个采用UTF-8,一个采用GB2312,不得已需要转换字符集。转换函数记录如下:
#include <iconv.h>
#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);


}





你可能感兴趣的:(Linux字符集,C程序输出汉字内码分析,读取数据库时汉字编码分析)