VC中使用Unicode的一些列问题
VC6.0中默认的是多字节编码,而自从VS2005以后都是默认的Unicode字符编码格式了。至于ANSI, MBCS(多字节编码)和UNICODE之间的区别可以百度一下。下面的一篇博文写的也比较详细:
http://www.tongji.net/index.php/uid-160994-action-viewspace-itemid-12415
大致说来:我们用C语言写的控制台程序里面大多都是多字节编码,其中英文字母是一个字节,中文是两个字节。而Unicode编码中英文和中文全是占两个字节。VC中用Unicode编码的一个好处就是MFC做的界面可以是操作系统的界面了(VC2008中还可以用更多的界面)。改用多字节编码的时候界面就是VC6.0里面那种98风格的界面了。这只是一个原因,更重要的原因是统一标准的问题,所以使用Unicode还是必要的。
最后的代码如下:
http://www.tongji.net/index.php/uid-160994-action-viewspace-itemid-12415
大致说来:我们用C语言写的控制台程序里面大多都是多字节编码,其中英文字母是一个字节,中文是两个字节。而Unicode编码中英文和中文全是占两个字节。VC中用Unicode编码的一个好处就是MFC做的界面可以是操作系统的界面了(VC2008中还可以用更多的界面)。改用多字节编码的时候界面就是VC6.0里面那种98风格的界面了。这只是一个原因,更重要的原因是统一标准的问题,所以使用Unicode还是必要的。
之前用 VC2008写程序的时候,在字符串前加_T就行了,例如:_T("呵呵呵!")就表示编译时看情况将字符串"呵呵呵!"转化为Unicode或者多字符编码格式。而L"呵呵呵!"表示将字符串"呵呵呵!"转换成Unicode。如今出现一个比较麻烦的问题,就是将Unicode的CString转换成 char[],主要是socket编程中sendto函数中遇到的。
参考一篇博文:http://cj0000.itpub.net/post/4086/483973
最后的代码如下:
//------------------------- 全局函数---------------------------
//将Unicode的 CString转换为多字节字符数组
string WideCharToMultiChar(wstring str)
{
string return_value;
//获取缓冲区的大小,并申请空间,缓冲区大小是按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, str.c_str(), str.size(), NULL, 0, NULL, NULL);
char *buffer = new char[len+1];
WideCharToMultiByte(CP_ACP, 0, str.c_str(), str.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
return_value.append(buffer);
delete [] buffer;
return return_value;
}
//------------------------- 全局函数---------------------------
void CChatDlg::OnBnClickedButtonSend()
{
// TODO: 在此添加控件通知处理程序代码
//获取对方IP
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
SOCKADDR_IN addrTo;
addrTo.sin_family = AF_INET;
addrTo.sin_port = htons(6000);
addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
CString strSend;
string tempSend;
//获取待发送数据
GetDlgItemText(IDC_EDIT_SEND, strSend);
//在Unicode下将CString转换成char*
tempSend = WideCharToMultiChar((LPCTSTR)strSend);
//发送数据
sendto(m_socket, tempSend.c_str(), tempSend.length()+1, 0, (SOCKADDR*)&addrTo, sizeof(SOCKADDR));
//清空发送框的内容
SetDlgItemText(IDC_EDIT_SEND, _T(""));
}
//将Unicode的 CString转换为多字节字符数组
string WideCharToMultiChar(wstring str)
{
string return_value;
//获取缓冲区的大小,并申请空间,缓冲区大小是按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, str.c_str(), str.size(), NULL, 0, NULL, NULL);
char *buffer = new char[len+1];
WideCharToMultiByte(CP_ACP, 0, str.c_str(), str.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
return_value.append(buffer);
delete [] buffer;
return return_value;
}
//------------------------- 全局函数---------------------------
void CChatDlg::OnBnClickedButtonSend()
{
// TODO: 在此添加控件通知处理程序代码
//获取对方IP
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
SOCKADDR_IN addrTo;
addrTo.sin_family = AF_INET;
addrTo.sin_port = htons(6000);
addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
CString strSend;
string tempSend;
//获取待发送数据
GetDlgItemText(IDC_EDIT_SEND, strSend);
//在Unicode下将CString转换成char*
tempSend = WideCharToMultiChar((LPCTSTR)strSend);
//发送数据
sendto(m_socket, tempSend.c_str(), tempSend.length()+1, 0, (SOCKADDR*)&addrTo, sizeof(SOCKADDR));
//清空发送框的内容
SetDlgItemText(IDC_EDIT_SEND, _T(""));
}
转换的时候比较重要的就是字符串中字符个数和字符串的结尾符号。
最后运行的比较成功。
另外,MSDN上有篇文章也很好,可以参考一下:http://msdn.microsoft.com/en-us/library/ms235631.aspx
还有一种方法将CString转换成char*,而前面的方法只能将CString通过string.c_str()转换成const char*。
先加入头文件:#include <afxconv.h>
CString strSend;
int len;
GetDlgItemText(IDC_EDIT_SEND, strSend);
#ifdef _UNICODE
//CString转换成char*
USES_CONVERSION;
wsabuf.buf = W2A(strSend);
wsabuf.len = strlen(wsabuf.buf)+1;
#else
len = strSend.GetLength();
wsabuf.buf = strSend.GetBuffer(len);
wsabuf.len = len+1;
#endif
int len;
GetDlgItemText(IDC_EDIT_SEND, strSend);
#ifdef _UNICODE
//CString转换成char*
USES_CONVERSION;
wsabuf.buf = W2A(strSend);
wsabuf.len = strlen(wsabuf.buf)+1;
#else
len = strSend.GetLength();
wsabuf.buf = strSend.GetBuffer(len);
wsabuf.len = len+1;
#endif
而在将char*转换成CString很方便:
char buf[200];
CString str(buf);