浅谈Python和VC中的编码问题(转)

以前编码问题总能让自己凑或蒙过去,最近要做一个项目服务器端用python写,客户端用c++,工程编译的字符集使用UNICODE。之间通过socket进行通信,通信过程中编码转换问题把我搞得晕头转向,逼着我将编码问题好好研究一番。


 
 

首先先谈谈VC中的编码问题,首先编码我们大致可以分为两类:文件编码和内存编码。文件编码即源代码文件的编码,gbk,UTF-8等。内存编码即源代码编译成为二进制文件的时候采用的编码。


比如,在VC 2008中我们写下如下的代码:


char* a = “a中”;


让我们分别来看一下文件编码和内存编码的区别。


用UntraEdit打开该cpp文件,进入十六进制模式:我们可以看到”a中”对应的编码为:0×61 0xD6 0xD0,0×61是ASCII码中的a,0xD6 0xD0是GBK里”中”的编码。说明,在中文windows环境下,VC创建的文件编码默认是GBK的。那么我们将文件修改为UTF-8的编码格式,重新用UE以十六进制模式进入。我们看到”a中”的编码变为了0×61 0xE4 0xB8 0xAD,0×61仍然是a的编码,而中的编码变成了,0xE4 0xB8 0xAD。


从上面的试验我们还可以知道,GBK中中文为2个字节,UTF-8是3个字节。


 
 

下面我们研究一下内存编码,内存编码在VC中只有3个选项:Not Set,Use Multi-Byte Character Set和Use Unicode Character Set。这个属性的修改可以在工程的属性栏中找到:

 

 

 
 

让我们继续观察上面的例子。来查看一下什么是内存编码。我们在程序中设置断点,调试程序来观察在程序运行过程中,三种工程属性下,char* a所指向的那篇内存空间的值是什么,是不是如我们所认为的那样:


工程属性
 Not Set
 Use Multi-Byte Character Set
 Use Unicode Character Set
 
内存
 0×61 0xd6 0xd0
 0×61 0xd6 0xd0
 0×61 0xd6 0xd0
 

 
 

如上表所示,无论工程属性如何设置,”中”在内存中都是gbk编码。这样的程序拿到非中文的操作系统中执行是会出现乱码的,那么怎么才能将其用UNICODE进行编码呢?我们需要用到wchar_t这个类型,wchar_t是一种宽字类型,宽字类型的变量使用方法如下wchar_t* a = L”a中”;即在”a中”前面加上L。


现在,调试一下可以看到,a在内存中的值为0×61 0×00 0×2d 0×4e。wchar_t类型的变量会将用两个字节存储英文变量,即在原有ASCII的基础上补上两个0.而后面的0×2d 0×4e就是”中”的编码。


这样,变量a就在多种语言平台上都可以正确显示了。那么,工程属性中的三种字符集选项有什么作用呢?


让我们引用MSDN中的原文:


Generic-text


data type name
 SBCS (_UNICODE,


_MBCS not


defined)
 _MBCS


defined
 _UNICODE


defined
 
_TCHAR
 char
 char
 wchar_t
 
_tfinddata_t
 _finddata_t
 _finddata_t
 _wfinddata_t
 
_tfinddata64_t
 __finddata64_t
 __finddata64_t
 __wfinddata64_t
 
_tfinddatai64_t
 _finddatai64_t
 _finddatai64_t
 _wfinddatai64_t
 
_TINT
 int
 int
 wint_t
 
_TSCHAR
 signed char
 signed char
 wchar_t
 
_TUCHAR
 unsigned char
 unsigned char
 wchar_t
 
_TXCHAR
 char
 unsigned char
 wchar_t
 
_T or _TEXT
 No effect (removed by preprocessor)
 No effect (removed by preprocessor)
 L (converts following character or string to its Unicode counterpart)
 

 
 

SBCS、_MBCS和_UNICODE是三个宏,会分别在设置了Not Set、Use Multi-Byte Character Set、Use Unicode Character Set的时候定义。为了程序的可移植性,我们通常不会直接使用wchar_t和L,而是使用TCHAR和T()。这样,在工程属性设置不同的情况下,TCHAR和T()会被解释为不同的内容。


同样,我们以前测试字符串长度的函数strlen也不要直接使用,为了可移植性,我们通常使用_tcslen或者_tcsclen。


 
 

TCHAR.H routine
 _UNICODE & _MBCS not defined
 _MBCS defined
 _UNICODE defined
 
_tcslen
 strlen
 strlen
 wcslen
 
_tcsclen
 strlen
 _mbslen
 wcslen
 
_tcsclen_l
 strlen_l
 _mbslen_l
 wcslen_l
 

 
 

那么现在的问题是,我想要把数据经过网络传输,现在是否可以直接传输wchar_t*的变量呢,答案是不行的,因为wchar_t*的字符串的英文字符表示中存在00,中文英文都用两个byte。这样既浪费空间又可能会导致网络的错误。因此我们需要先将其转换成char*的那种类型,即,英文用一个byte,中文用两个byte。怎么转换呢?要使用MultiByteToWideChar和WideCharToMultiByte来互相进行转换。转换完了之后再通过网络传输。


 
 

 
 

好了,现在数据到了Python端,想想看,现在Python端收到的是什么编码?对,中文是gbk的编码。然后我们为了在python端实现国际化,要将gbk转化成unicode。方法很简单,首先先用


s = struct.unpack(’s’,mysocket.recv(2))来接收一个中文字,然后调用s.decode(”gbk”)来将编码转化成为unicode编码。这样,编码问题就完全解决了~

 

VC++.NET中字符串之间的转换
2007-09-28 20:51
一、BSTR、LPSTR和LPWSTR

  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。

  那么什么是BSTR、LPSTR以及LPWSTR呢?

  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的 API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。

  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘/0’)结尾的8位ANSI 字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、 LPCTSTR等,它们的含义如图2所示。

  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。

  一般地,还有下列类型定义:

#ifdef UNICODE
 typedef LPWSTR LPTSTR;
 typedef LPCWSTR LPCTSTR;
#else
 typedef LPSTR LPTSTR;
 typedef LPCSTR LPCT

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值