彻底搞定char/wchar_t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(2013-07-17 10:18:28)从char/wchar_t到TCHAR(1)(发表时间: 2008-4-26 0:54:00)
【评论】 【打印】 【字体:大 中 小】 本文链接:http://blog.pfan.cn/xman/34551.html 复制链接
标签:字符串处理
一.ANSI和UNICODE
1.为什么要使用Unicode?
(1) 可以很容易地在不同语言之间进行数据交换。
(2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。
(3) 提高应用程序的运行效率。
Windows 2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。
Windows 98只支持ANSI,只能为开发ANSI应用程序。 Windows CE 就是使用Unicode的操作系统,完全不支持ANSI版函数。
Microsoft将COM从Win16转换成Win32时,所有COM接口方法都只能接受Unicode字符串。
2.ANSI字符和Unicode字符
ANSI字符类型为CHAR,指向字符串的指针PSTR(LPSTR),指向一个常数字符串的指针PCSTR(LPCSTR);对应的Windows定义的Unicode字符类型为WCHAR(typedef WCHAR wchar_t),指向Unicode字符串的指针PWSTR ,指向一个常数Unicode字符串的指针PCWSTR 。
ANSI “ANSI”
Unicode L“UNICODE”
ANSI/Unicode T(“string”)或_TEXT(“string”)
3.ANSI字符和Unicode字符串的操作
双字节(DBCS)字符集中,字符串的每个字符可以包含一个或两个字节。如果只是调用strlen()函数,那么你就无法知道字符串到底有多少个字符,它只能告诉你到达结尾的0之前有多少个字节。
标准c中的strcpy,strchr,strcat等只能用于ANSI字符串,不能正确处理Unicode字符串,因此也提供了一组补充函数,功能等价,但用于Unicode码。我们来看看string .h字符串头文件中是怎样处理char*和wchar_t*两个字符串版本的:
// …Microsoft Visual Studio 8VCincludestring.h
char *strcat(char*,const char*);
wchar_t *wcschr(wchat_t*, const wchar_t*);
类似的还有strchr/wcschr,strcmp/wcscmp,strlen/wcslen etc. ANSI 操作函数以str开头 strcpy ,Unicode 操作函数以wcs开头 wcscpy
MBCS 操作函数以_mbs开头 _mbscpy
ANSI/Unicode 操作函数以_tcs开头 _tcscpy(C运行期库)
ANSI/Unicode 操作函数以lstr开头 lstrcpy(Windows API)
所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。
二.ANSI/UNICODE通用字符/字符串类型TCHAR/LPTSTR/LPCTSTR
Neutral ANSI/UNICODE types
1.通用字符型TCHAR
ifdef UNICODE it is wchar_t(WCHAR)for Unicode platforms;
else it is char for ANSI and DBCS platforms.
2.通用字符串指针LPTSTR
ifdef UNICODE it is LPWSTR(*wchar_t) for Unicode platforms;
else it is LPSTR (*char) for ANSI and DBCS platforms.
3.通用通用常数字符串指针LPCTSTR
ifdef UNICODE it is LPCWSTR(*const wchar_t) for Unicode platforms;
else it is LPCSTR (*const char) for ANSI and DBCS platforms.
typedef LPWSTR LP;
#define __TEXT(quote) L##quote // r_winnt
<1>_UNICODE宏用于C运行期头文件,UNICODE宏则用于Windows头文件,当编译代码模块时,通常必须同时定义这两个宏。
<2>如果定义了_UNICODE,若要生成一个Unicode字符串,字符串前要加L宏,用于告诉编译器该字符串应该作为Unicode字符串来编译处理。但是这样又有个问题就是如果没有定义_UNICODE则编译出错。为了解决这个问题我们必须用到_TEXT宏,这个宏也在TChar.h中做了定义。使用该宏后,无论源文件有没有定义_UNICODE都不会出现编译错误。
<3>Unicode与ANSI字符串的转换:Windows函数MultiByteToWideChar/mbstowcs函数用于将多字节字符串转换成宽字符串,函数WideCharToMultiByte/wcstombs将宽字符串转换成等价的多字节字符串。
三.ANSI/UNICODE字符串通用函数lstrcmp/lstrcpy/lstrcat/lstrlen
// …Microsoft Visual Studio 8VCPlatformSDKIncludeWinbase.h -- 已经包含在windows.h中。
lstrcmp(lstrcmpi)
WINBASEAPI
int
WINAPI
lstrcmpA(
__in LPCSTR lpString1,
__in LPCSTR lpString2
);
WINBASEAPI
int
WINAPI
lstrcmpW(
__in LPCWSTR lpString1,
__in LPCWSTR lpString2
);
#ifdef UNICODE
#define lstrcmp lstrcmpW
#else
#define lstrcmp lstrcmpA
#endif // !UNICODE
lstrcpy
WINBASEAPI
__out
LPSTR
WINAPI
lstrcpyA(
__out LPSTR lpString1,
__in LPCSTR lpString2
);
WINBASEAPI
__out
LPWSTR
WINAPI
lstrcpyW(
__out LPWSTR lpString1,
__in LPCWSTR lpString2
);
#ifdef UNICODE
#define lstrcpy lstrcpyW
#else
#define lstrcpy lstrcpyA
#endif // !UNICODE
另外还有lstrcat(W/A)和lstrlen(W/A),这里未列出其函数定义。
四.使用shlwapi头文件中定义的函数StrCat/StrCmp/StrCpy
shlwapi.dll是UNC和URL地址动态链接库文件,用于注册键值和色彩设置。因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。这将有助于稍稍提高应用程序的运行性能。
// …Microsoft Visual Studio 8VCPlatformSDKIncludeshlwapi.h
注意:使用StrCat、StrCmp、StrCpy etc时要#include "shlwapi.h"
LWSTDAPI_(LPWSTR) StrCatW(LPWSTR psz1, LPCWSTR psz2);
LWSTDAPI_(int) StrCmpW(LPCWSTR psz1, LPCWSTR psz2);
LWSTDAPI_(LPWSTR) StrCpyW(LPWSTR psz1, LPCWSTR psz2);
#ifdef UNICODE
#define StrCat StrCatW
#define StrCmp StrCmpW
#define StrCpy StrCpyW
#else
#define StrCat lstrcatA
#define StrCmp lstrcmpA
#define StrCpy lstrcpyA
etc
参考:
《VC中的__T宏》http://www.diybl.com/course/3_program/vc/vc_js/2008830/138819.html
下一篇:《从char/wchar_t到TCHAR(2)》
阅读(7308) | 评论(1) | 复制链接
关于Unicode支持,wchar_t * 到 char *的转换
(2008-03-28 14:44:33)CString origCString("Hello,World"); char* CharString = origCString.GetBuffer(origCString.GetLength()+1); 在VC++2008中编译得到下列信息: Error 1 error C2440: 'initializing' : cannot convert from 'wchar_t *' to 'char *'
又是该死的Unicode作怪。一查看,果然如此,vc++2008默认打开了对unicode的支持……,
CString对应的字符串应该是TCHAR,TCHAR的定义是这样的, #ifdef _UNICODE typedef wchar_t TCHAR ; #else typedef char TCHAR; #endif
查阅MSDN,发现一篇好文章:“How to: Convert Between Various String Types”,http://msdn2.microsoft.com/en-us/library/ms235631.aspx。
其中将wchar_t*转换为char*的代码如下:(为了保持文章的一致性,修改了变量名) #include #include using namespace std; int main() { wchar_t *origString = L"Hello,World"; wcout << origString << endl; // Convert to a char* size_t origsize = wcslen(origString) + 1; const size_t newsize = 100; size_t convertedChars = 0; char CharString[newsize]; wcstombs_s(&convertedChars, CharString, origsize, origString , _TRUNCATE); cout << CharString << endl; } 输出正确,均为Hello, World!
结合上面的两段,看看能不能将CString转换为char* CString origCString("Hello, World!"); wchar_t* wCharString = origCString.GetBuffer(origCString.GetLength()+1); size_t origsize = wcslen(wCharString) + 1; size_t convertedChars = 0; char *CharString; CharString=new char(origsize); wcstombs_s(&convertedChars, CharString, origsize, wCharString , _TRUNCATE); cout << CharString << endl; 成功输出字符串"Hello,World" 。
真是太麻烦了,还是将unicode支持关闭吧。工程名—〉属性—〉常规中的 字符集 中选择 未设置。
编程中的多字节和Unicode
在编译许多程序的时候,我们常常会出现诸如指针转换错误或者const char[] 不能转换成XX的错误,这时很可能就是项目编码的问题了,如果您使用的是VS编程环境,那么打开工程属性,里面就有个选项是给你选择采用多字符集还是采用 unicode。而对于这两者,我坚定不移的喜欢unicode~
在多字节环境下,系统会按照ASCII字符表中128个字符进行截断操作,由于汉字是占用两个的字节的,所以在即有汉字又有英文的字符串中,该函数只会截断字符串右边英文字符,而对于汉字则无法处理。
而对于Unicode字符集使用两个字节对世界上几乎所有的语言进行编码(0×0000-0xFFFF),它可以表达的字符数量为16位,即 65536个字符,每种语言的代码段不同,两个字节所表达的字符是唯一的,所以在该环境下,每一个字符都有唯一的一个编码,那么在进行截断操作时,自然不会出现意料之外的结果。 而我看过好几本有名气的C++的书中,都是说到一个项目或者程序的编码最好都选择Unicode(可是在几本国内出的书里不但没提及,而且提供的源代码也全都是“多字节”的),在此,我并没有鄙视多字节的意思,只是觉得写出通用的,跨语言的代码时候最好采用unicode。
下面这段话是来自MSDN:
要完成应用程序的 Unicode 编程,还必须:
使用 _T 宏有条件地编写字符串的代码,使之可移植到 Unicode。 当传递字符串时,请注意函数参数要求的长度是以字符为单位还是以字节为单位的。如果在使用 Unicode 字符串,这一区别是很重要的。 使用 C 运行时字符串处理函数的可移植版本。 使用以下用于字符和字符指针的数据类型: TCHAR 这里将使用 char。 LPTSTR 这里将使用 char*。 LPCTSTR 这里将使用 const char*。CString 提供 operator LPCTSTR 来在 CString 和 LPCTSTR 之间进行转换。 CString 还提供识别 Unicode 的构造函数,赋值运算符和比较运算符。
呵呵~补充一点就是使用_T的时候,如果系统提示你它是没有定义的标识符的话,带上atlstr.h就ok了。哈,又是一个笔记~
关于Windows中ANSI和Unicode的转换
(2008-01-09 11:09:12转载▼
标签:
杂谈 |
分类: MSN搬家 |
MFC在testView.cpp这样写一段:
void Ctest3View::OnDraw(CDC* pDC) { Ctest3Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return;
// TODO: 在此处为本机数据添加绘制代码 pDC->TextOut(0,0,_T("你好世界!"));
// pDC->TextOut(0,0,L"你好世界!"); pDC->SelectStockObject(GRAY_BRUSH); pDC->Ellipse(CRect(0,20,100,120)); }
以上的_T("aaa")和L"aaa"到底有什么差别呢?
Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。Windows NT的所有与字符有关的函数都提供两种方式的版本,而Windows 9x只支持ANSI方式。_T一般同字常数相关,如_T("Hello")。如果你编译一个程序为ANSI方式,_T实际不起任何作用。而如果编译一个程序为UNICODE方式,则编译器会把"Hello"字符串以UNICODE方式保存。_T和_L的区别在于,_L不管你是以什么方式编译,一律以以 UNICODE方式保存。
在微软的丛书中有一部分是这么写的:按如下方式将字符串常量编码: "HELLO" 那么编译器将从ansi字符串中组成该字符串。 如果是 L"HELLO" 那么编译器将使用Unicode编码。 如果使用MFC的_T宏_T("HELLO"),其中 如果定义了预处理符号_UNICODE,那么编译器将使用Unicode字符。 如果没有定义的话,就使用ansi字符。