VS下使用多字符集编码和Unicode字符集编码的总结

VS下使用多字符集编码和Unicode字符集编码的总结编写 MFC 程序的时候 总遇到字符集转换的问题 这里总结一下 方便大家使用 在多字节字符集编码下 设置如下环境 这时 CString 与 char 数组是可以互相转换的 而如果改成 使用 Unicode 字符集 设置如下 原来的代码就会报很多错误 诸如 errorC2664 Cxxxxx ConvertStrin 不能将参数 1 从 wchar t 转换为 char

AfxMessageBox("编码类型不正确!"); 

改为

AfxMessageBox(_T("编码类型不正确!")); 
strTest.Replace(" ", ""); 

改为

strTest.Replace(_T(" "), _T("")); 
WORD cbBufMax = 2000; WORD cbBufOut; #ifdef UNICODE char szBuf[2001]; char *pszBuf = szBuf; // Get the names of the installed drivers ("odbcinst.h" has to be included ) if(!SQLGetInstalledDrivers(szBuf, cbBufMax, & cbBufOut)) { m_sExcelDriver = ""; } #else wchar_t szBuf[2001]; wchar_t *pszBuf = szBuf; // Get the names of the installed drivers ("odbcinst.h" has to be included ) if (!SQLGetInstalledDrivers(szBuf, cbBufMax, &cbBufOut)) { m_sExcelDriver = _T(""); } #endif 

对于一些操作字符和字符串的库函数,也是有区别的:

#ifdef UNICODE // Search for the driver... do { if (wcsstr(pszBuf, _T("Excel")) != 0) { // Found ! m_sExcelDriver = CString(pszBuf); break; } pszBuf = wcschr(pszBuf, '\0') + 1; } while (pszBuf[1] != '\0'); #else // Search for the driver... do { if( strstr( pszBuf, "Excel" ) != 0 ) { // Found ! m_sExcelDriver = CString( pszBuf ); break; } pszBuf = strchr( pszBuf, '\0' ) + 1; } while( pszBuf[1] != '\0' ); 

为了有更好的兼容性,应该选择两个版本通用的函数,比如字符串转长整形,最好使用_tcstol函数来代替使用跟字符集相关的strtol或wcstol函数,类似的还有_ttoi、_ttof之类的转换函数。

在Unicode字符集下写文件的时候,对于长度操作要注意,一个宽字符是要写两个长度的:

 CFile fileSave; CString strGetData(_T("写入测试")); CString strPath(_T("test.txt")); if (!fileSave.Open(strPath, CFile::modeCreate |CFile::modeNoTruncate | CFile::modeWrite)) { return; } wchar_t wch = 0xFEFF; fileSave.Write(&wch, sizeof(wchar_t)); fileSave.Write(strGetData.LockBuffer(), wcslen(strGetData)*2); strGetData.UnlockBuffer(); fileSave.Close(); 

使用Unicode字符集还有一大问题,就是CString与char之间的相互转换,以下函数就我总结的转换函数,char转CString函数:

CString Char2CString(char *pChar) { int charLen = strlen(pChar); // 计算pChar所指向的字符串大小 int len = MultiByteToWideChar(CP_ACP, 0, pChar, charLen, NULL, 0); // 计算多字节字符的大小 wchar_t *pWChar = new wchar_t[len + 1]; // 为宽字节字符数申请空间 MultiByteToWideChar(CP_ACP, 0, pChar, charLen, pWChar, len); // 多字节编码转换成宽字节编码 pWChar[len] = '\0'; // 将wchar_t数组转换为CString CString str; str.Append(pWChar); delete[] pWChar; return str; } 

CString转char*函数:

char* CString2Char(CString str) { DWORD dwCount = str.GetLength(); int len = WideCharToMultiByte(CP_ACP, 0, str, dwCount, NULL, 0, NULL, NULL); // 获取宽字节字符的大小 char *pChar = new char[len + 1]; WideCharToMultiByte(CP_ACP, 0, str, dwCount, (char *)pChar, len, NULL, NULL); // 宽字节编码转换成多字节编码 pChar[len] = '\0'; // 注意以'\0'结束 return pChar; } 

从代码可以看出,这里CString转char*需要new一个内存空间,使用后得记得delete掉才行。如果不习惯释放空间,那CString转char时最好不要开辟空间,万一忘记delete就造成内存泄露了,可以写一个改进版的转换函数:

static int CStrintToCharWithoutNew(CString str, char *buf) { int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); if (len > 0) WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL); buf [len] = '\0'; // 注意以'\0'结束 return len; } 

这样使用后就不需要再记得delete了,前提是数组得定义的足够大:

char recvData[200]; CString testdata = _T("测试转换"); len = CStrintToCharWithoutNew(testdata, recvData); 

上面的方法虽然基础,但显得麻烦了些,char*转CString只需要使用A2T()或A2W()宏即可:

char cBuf[] = "hello 世界"; CString str = _T(""); USES_CONVERSION; str = A2T(cBuf); // str = A2W(cBuf); 

如果项目没包含头文件#include <atlconv.h>需要自己加上,USES_CONVERSION宏一定要放在使用前,否则会报错:

error C2065: “_lpa”: 未声明的标识符 

类似的CString转char只需使用T2A或W2A宏即可。对于网上说的char转CString使用Format方法,如下:

char cBuf[] = "hello 世界"; CString str = _T(""); str.Format(_T("%s"), cBuf); 

经测试,在Unicode编码下是不行的,cBuf数组就不是宽字符,改为下面写法就可以了:

str.Format(_T("%s"), _T("hello 世界")); 

有时函数的参数是指针类型LPTSTR(多字符下是char ,Unicode下实际是wchar_t),那么如何把CString转为LPTSTR呢,下面两种方法都可以:

CString str("hello 世界"); LPTSTR lp = (LPTSTR)(LPCTSTR)str; // LPTSTR lp = str.GetBuffer(); 

上面的代码在多字符集和Unicode字符集下都可以使用的,不过使用GetBuffer()时,使用完记得调用ReleaseBuffer()释放内存。这里有个细节,细心的读者可能会发现,CString创建的时候没有加_T宏:

CString str(_T("hello 世界")); 

这里CString的构造函数自动为我们处理了,所以不用担心编码问题的。说到这里,您一定对_T宏感兴趣了,这个宏到底做了什么呢?在tchar.h文件中可以看到对它的定义,摘录下来如下:

#define _T(x) __T(x) #define _TEXT(x) __T(x) #define __T(x) L x // 编码为 Unicode #define __T(x) x // 编码为 多字符 

其实它根据不同的编码环境来转换字符的,在Unicode下,会把字符前面加个L代表宽字符,所以下面的定义只能在Unicode下使用:

wchar_t wBuf[] = _T("hello 世界"); 

就等同于:

wchar_t wBuf[] = L"hello 世界"; 

L为宽字符的定义宏,调试时可以发现宽字符变量的值是带L的。而在多字符集下面就报错了,因为转义成了:

wchar_t wBuf[] = "hello 世界; 

有时候会见到WCHAR和TCHAR宏,不用慌,其实他们也是wchar_t的变体,类似很多宏定义都可以在WinNT.h文件中找到。说到TCHAR,有必要说明一下,是MFC为了统一字符集操作而定义的类型,它跟_T宏类似,在不同的字符集下有不同的定义:

typedef wchar_t TCHAR; // 编码为 Unicode typedef char TCHAR; // 编码为 多字符 

那么对于刚才的问题就有了解决方案,定义数组时如下定义:

TCHAR tBuf[] = _T("hello 世界"); 
typedef LPCWSTR PCTSTR, LPCTSTR; typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR; 

分析可见在Unicode下实际上是WCHAR 类型,而那个库原本在多字符集条件下编译时应该转为LPCSTR(实际上是char)类型的:

typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR; 

所以对于对外接口来说,写成通用字符集的参数是很不好的,人家编译时选择的字符集不一定和你一样,很容易造成连接错误的,直接写成char*类型才是正道啊。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231373.html原文链接:https://javaforall.net

(0)
上一篇 2026年1月15日 上午8:01
下一篇 2026年1月15日 上午8:22


相关推荐

  • HTTP请求返回415错误码定位解决

    HTTP请求返回415错误码定位解决今天在工作中,发现我再调用外部API接口的时候,发现一个奇怪的问题,就是我Eclipse中写代码调用外部API接口时返回HTTP状态码是415,但是我将相同的报文放在HttpRequester里面请求的时候却又可以拿到正常返回结果,而不是415错误。不知道有没有人跟我一样遇到过这个问题,这里记录一下解决办法。首先我们还是看下HTTP的状态码关于415返回码的说明吧。41

    2022年6月14日
    47
  • JavaScript 模块化编程

    JavaScript 模块化编程简介 模块化就是 js 与 js 之间的调用 类似于 Java 类与类之间的调用 使用模块化可以使项目结构更加清晰明了 代码更加优雅 es5 写法 demo1 js 定义方法 consthello function return hello constok function return ok 指定哪些方法可以被调用 module exports hello ok demo2 js 引入要调用的文件 constm require demo1

    2026年3月17日
    1
  • Oracle Hints具体解释

    Oracle Hints具体解释

    2021年12月9日
    48
  • HTML的注释与JavaScript注释及快捷键「建议收藏」

    HTML的注释与JavaScript注释及快捷键「建议收藏」1、单行注释:在代码前输入两个反斜杠//,或用快捷键ctrl+/2、多行注释:使用/**/把要注释的代码块包起来,或用快捷键shift+alt+a3、若觉得2、的快捷键用着不方便,可以按自己喜欢可以在vscode中修改注释快捷键。…

    2022年5月29日
    27
  • noip2012提高组初赛_noip2018提高组初赛解析

    noip2012提高组初赛_noip2018提高组初赛解析Noip2012参赛总结又一年NOIP考完了。刚刚才看了去年自己写的参赛总结,有点后悔考试之前没有看。里面有一句话“NOIP给的数据都是白痴的,一定要多测几组自己的数据,尽管有些数据你相信你的程序一定能过。但往往正是这些数据暴露出了你程序的不足。”对于DAY1的第二题。我想用深搜来做,尽管我知道过不了多少个点,但总比没有好。于是就以很快的速度敲完了深搜,测了两组数据就去做第三题了。离考试

    2022年8月22日
    7
  • 如何用51单片机控制步进电机运动

    如何用51单片机控制步进电机运动本来接触单片机挺久了的,但是一直只是停留在非常初级的认识阶段,本科的时候上过几门课,但是从来没有自己捣鼓过单片机,这次突然来了兴趣,感觉一下子学到了好多东西,在这里好好整理一下。这篇文章只适合于入门阶段的小白阅读,高手请绕道。12年年初的时候购买了一套普中科技的“单片机开发试验仪”,好多次想好好学学,结果每一次都半途而废,主要原因还是周围的人都不会用,有问题都不知道找谁问,结果锁到箱子里一直到现在。

    2022年6月1日
    33

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号