一文讲清楚Windows Mobile和Wince(Windows Embedded CE)的字符集问题

转自 http://www.cnblogs.com/procoder/archive/2009/11/25/windows-mobile-ansi-unicode-string.html

 

背景

开发过Windows Mobile和Wince(Windows Embedded CE)的开发者,特别是Native C++开发者,或多或少都遇到过ANSI字符集和Unicode字符集的转换问题。本文试图把Windows Mobile和Wince(Windows Embedded CE)开发的字符集问题讲明白,其实这个题目有点ambitious和aggressive,就当成标题党吧。

 

简介

本文试图通过一篇文章讲清楚Windows Mobile和Wince(Windows Embedded CE) Native C++开发中字符集的转换问题。从字符集的概念入手,讲述Wince支持的所有字符串类型,以及各种类型的转换方法,最后给出使用建议。

 

什么是字符集

字符集(Character Set)是映射关系,其定义了字符和编码的关系。这里编码通常来说是1和0的bit。当前流行的计算机系统任何数据存储最终都表达为1和0。而这些1和0在不同字符集下映射成不同含义的字符。

计算机发明和使用初期,存储设备都十分的昂贵,科学家们想尽办法来节省成本,因此开始的是,最常见的字符集是单字节字符集(Signle-byte),所谓单字节字符集就是使用一个byte来代表一个字符,单字符集的典型是ASCII (American Standard Code for Information Interchange),你看这不是国籍标准,仅仅是美国标准,压根就没有考虑咱们感受,咱们从甲骨文开始发展汉字,美国人看到就A~Z几个字母。

asciifull

这个ASCII 表,学过C语言的人都学过,以前考试也用到,需要背下来的。

ANSI(American National Standards Institute) 是在ASCII 7bit 编码标准 (ASA X3.4-1963)的基础上,加入了欧洲字母发展出来的一个标准。

但是单字节字符集有个最要命的缺点是一个byte只要8个bit,也就是最多表示256 (28)个可见和不可见的字符。 对于英语国家可能是够用的,但是对于说中文的国家,汉字是没办法通过256个字符表达的。因此慢慢出来国际标准的字符集Unicode。

 

Wince与Unicode

对于刚刚接触Windows Mobile和Wince(Windows Embedded CE) Native C++开发的人来说,会有这样的想法:Windows Mobile和Wince仅仅支持Unicode,不支持ANSI的。TinyXML是使用ANSI string的,但是Wince使用Unicode,那么TinyXML不能使用在Wince和Windows Mobile中。等等…… 其实这些想法有些错误,Wince是一个Unicode系统,没错,这表示Wince里面所有字符串处理代码都是基于Unicode编码,但是不表示Wince不支持ANSI。我们同样可以继续在Wince中使用ANSI,例如使用std::string, char[]等。

但是为什么会有这些误区呢,先看一下下面的编译错误。

error C2664: 'wprintf' : cannot convert parameter 1 from 'const char [21]' to 'const wchar_t *'

 

error C2664: 'DeleteFileW' : cannot convert parameter 1 from 'const char [21]' to 'LPCWSTR'

我敢保证刚刚接触Windows Mobile和Wince(Windows Embedded CE) Native C++开发的人10个有9个甚至10个都碰到过上述问题。在调用Win32 API的时候,使用MFC,WTL的接口的时候都会碰到这样的问题,因为我们习惯使用char*,std::string,但是恰恰Win32 API,MFC和WTL的函数入口中的字符串为Unicode,因此发生上述的编译错误。不知道为什么大家碰到这个错误后会形成一个错误的想法:Wince只是支持Unicode,不支持ANSI了。其实Wince还是支持ANSI的,我们定义单字符的char数组,甚至可以通过C Runtime在Console中打印出ANSI string。

char ansiStr[] = "I am ANSI string";
printf(ansiStr);

 

Wince支持的字符串

既然Wince支持ANSI和Unicode,那什么时候用ANSI,什么时候用Unicode,下面我从在Wince开发中常常用到字符串讲起,然后讲述字符串的转换以及使用建议。

char*

char*和char[]没有本质的区别,都是指向内存的指针。ANSI版本的Win32的API中的字符串都是使用char*。 由于Win32的API是语言无关的,因此这些参数其实传递的是一段应该存放字符串的内存的指针。(很拗口,但是确实这样,呵呵)。在ANSI环境下使用纯粹C开发,程序是离不开char*的。

 

wchar_t *

LPWSTR, PWSTR等宏定义其实都是wchar_t*的定义, 最常见的LPCWSTR是const wchar_t*的宏定义。wchar_t表示16位Unicode字符。wchar_t*和wchar_t[]用来定义Unicode字符串。在Unicode版本下,所有Win32的API的字符串都由char*变成了wchar_t*了。

这个可以看一下头文件的预编译。例如以winbase.h的DeleteFile API为例。

WINBASEAPI
BOOL
WINAPI
DeleteFileA(
    LPCSTR lpFileName
    );
WINBASEAPI
BOOL
WINAPI
DeleteFileW(
    LPCWSTR lpFileName
    );
#ifdef UNICODE
#define DeleteFile  DeleteFileW
#else
#define DeleteFile  DeleteFileA
#endif // !UNICODE

在ANSI版本DeleteFile为DeleteFileA,参数的字符串定义为LPCSTR,也就是const char*,而Unicode版本的DeleteFile为DeleteFileW,参数字符串定义变成了LPCWSTR,也就是const wchar_t*。

 

决定DeleteFile到底是DeleteFileA或者DeleteFileW是由预编译宏 UNICODE 来决定的。

这个宏可以在项目属性里面配置,如下图:

ANSI-Unicode-1 

当选择Use Unicode Character Set时候,预编译会增加宏UNICODE和_UNICODE。

ANSI-Unicode-2

但是需要注意的是,如果目标平台为Windows Mobile或者Wince,不管是否选择Use Unicode Character Set,UNICODE和_UNICODE的预编译都会加上,也就是说Wince下所有Win32 API都是Unicode版本的。

 

CString

CString最初在MFC里面封装,ATL和WTL分别封装了CString,这三个不同封装的CString具有语义兼容性,也就是他们提供的接口是相同的。使用CString的好处是可以同时兼容ANSI和Unicode,如下例子:

CString str = "Independent String";
m_wndPic.SetWindowText(str);

m_wndPic是一个CStatic控件,上面的代码不管在ANSI或者在Unicode都能使用,无需更改。

 

下面以ATL CString为例子讲述CString是如何同时支持支持ANSI或者Unicode的。

typedef CAtlString CString;
typedef CStringT< TCHAR, StrTraitATL< TCHAR > > CAtlString;

CString存储字符串的类型由TCHAR来决定的,而TCHAR又是由UNICODE预编译来决定,见下面的宏定义。

#ifdef  UNICODE                     // r_winnt
typedef WCHAR TCHAR, *PTCHAR;
#else   /* UNICODE */               // r_winnt
typedef char TCHAR, *PTCHAR;
#endif /* UNICODE */   

以此CString使用字符串类型根据预编译选项来自动决定。

 

std::string

STL里面的string,封装的是单字节字符,由于其跨平台的特性,我编写的代码中大量使用std::string,其实准确来说我大量使用STL。例如我一般使用std::string来操作TinyXML。抛开Wince平台不说,使用std::string基本上没有缺点,可以跨任何支持标准C++的平台。可是在Wince和Windows Mobile下做开发,情况有点不一样,因为std::string封装的是单字节字符,所以如果需要调用Win32的API,使用MFC,ATL和WTL的功能时都需要转型,这姑且算是一个缺点吧,但是熟悉了转换以后,使用std::string一点问题都没有。

 

std::wstring

STL里面的string的Unicode版本,和std::string一样,使用了unicode字符进行封装。其实std::wstring我用的不多,用std::string已经够了。

 

如何转换Wince支持的字符串

既然Windows Mobile和Wince(Windows Embedded CE)支持上述的字符串,那么我们开发的时候会碰到这些字符串直接相互转换的问题,下面通过例子演示如何转换。

 

转换过程我推荐使用ATL的宏,关于ATL的宏可以参考  ATL and MFC String Conversion Macros

这些宏的命名规范为

CSourceType2[C]DestinationType[EX]

SourceType/DestinationType

Description

A

ANSI character string.

W

Unicode character string.

T

Generic character string (equivalent to W when _UNICODE is defined, equivalent to A otherwise).

OLE

OLE character string (equivalent to W).

 

A表示ANSI string,W表示Unicode string,T表示通用string,根据预编译来决定类型。OLE和W一样,我从来不用OLE。

例如CT2CA就是通用string转成ANSI string。

 

转换到char*

void ConvertToCharArray()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    CString cstr("ATL CString");

    std::string stlStr("STL string");
    std::wstring stlWStr(_T("STL wstring"));    //use _T() convert const string to wchar_t string

    printf("All string convert to char*\n");
    strcpy(ansiStr, CT2CA(unicodeStr));
    printf("Convert from wchar_t*, %s\n", ansiStr);

    strcpy(ansiStr, CT2CA(cstr));
    printf("Convert from CString, %s\n", ansiStr);

    strcpy(ansiStr, stlStr.c_str());
    printf("Convert from std::string, %s\n", ansiStr);

    strcpy(ansiStr, CT2CA(stlWStr.c_str()));
    printf("Convert from std::wstring, %s\n", ansiStr);
}

例子中用到了ATL CString,如果新建的是Win32项目需要加入ATL支持,方法可以参考: 在Windows Mobile和Wince(Windows Embedded CE)下Win32项目加入ATL支持

上面讲过ATL CString和WTL以及MFC CString语义相同,因此本文所有CString的代码在MFC下同样有效。

ANSI-Unicode-3

 

转换到wchar_t*

void ConvertToWCharArray()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    CString cstr("ATL CString");

    std::string stlStr("STL string");
    std::wstring stlWStr(_T("STL wstring"));    //use _T() convert const string to wchar_t string

    printf("All string convert to wchar_t*\n");
    wcscpy(unicodeStr, CComBSTR(ansiStr));
    wprintf(_T("Convert from char*, %s\n"), unicodeStr);

    wcscpy(unicodeStr, cstr);
    wprintf(_T("Convert from CString, %s\n"), unicodeStr);

    wcscpy(unicodeStr, CComBSTR(stlStr.c_str()));
    wprintf(_T("Convert from std::string, %s\n"), unicodeStr);

    wcscpy(unicodeStr, stlWStr.c_str());
    wprintf(_T("Convert from std::wstring, %s\n"), unicodeStr);
}

这里使用了微软推荐的CComBSTR(),而不是CA2W()。

ANSI-Unicode-4

转换到CString

void ConvertToCString()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    CString cstr("ATL CString");

    std::string stlStr("STL string");
    std::wstring stlWStr(_T("STL wstring"));    //use _T() convert const string to wchar_t string

    printf("All string convert to CString\n");
    cstr = ansiStr;
    wprintf(_T("Convert from char*, %s\n"), cstr);

    cstr = unicodeStr;
    wprintf(_T("Convert from wchar_t*, %s\n"), cstr);

    cstr = stlStr.c_str();
    wprintf(_T("Convert from std::string, %s\n"), cstr);

    cstr = stlWStr.c_str();
    wprintf(_T("Convert from std::wstring, %s\n"), cstr);
}

 ANSI-Unicode-5

转换到std::string

void ConvertToStlString()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    CString cstr("ATL CString");

    std::string stlStr("STL string");
    std::wstring stlWStr(_T("STL wstring"));    //use _T() convert const string to wchar_t string

    printf("All string convert to STL string\n");
    stlStr = ansiStr;
    printf("Convert from char*, %s\n", stlStr.c_str());

    stlStr = CT2CA(unicodeStr);
    printf("Convert from wchar_t*, %s\n", stlStr.c_str());

    stlStr = CT2CA(cstr);
    printf("Convert from CString, %s\n", stlStr.c_str());

    stlStr = CT2CA(stlWStr.c_str());
    printf("Convert from std::wstring, %s\n", stlStr.c_str());
}

 ANSI-Unicode-6

转换到std::wstring

void ConvertToStlWstring()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    CString cstr("ATL CString");

    std::string stlStr("STL string");
    std::wstring stlWStr(_T("STL wstring"));    //use _T() convert const string to wchar_t string

    printf("All string convert to STL wstring\n");
    stlWStr = CComBSTR(ansiStr);
    wprintf(_T("Convert from char*, %s\n"), stlWStr.c_str());

    stlWStr = unicodeStr;
    wprintf(_T("Convert from wchar_t*, %s\n"), stlWStr.c_str());

    stlWStr = cstr;
    wprintf(_T("Convert from CString, %s\n"), stlWStr.c_str());

    stlWStr = CComBSTR(stlStr.c_str());
    wprintf(_T("Convert from std::string, %s\n"), stlWStr.c_str());
}

 

ANSI-Unicode-7

 

纯C Runtime库转换

有时候使用Win32进行纯C的开发,例如进行今日插件的开发,不使用ATL,WTL,MFC以及STL的情况下,也会有转换char*和wchar_t*的需求,但是不能使用ATL的宏,下面演示如何使用C Runtime库来转换。

void ConvertToWCharArrayUsingCRuntime()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    printf("Convert to char* from wchar_t* using C Runtime library.\n");
    sprintf(ansiStr, "%S", unicodeStr);
    printf("Convert from wchar_t*, %s\n", ansiStr);
}

void ConvertToCharArrayUsingCRuntime()
{
    char ansiStr[255] = "ANSI string";
    wchar_t unicodeStr[255] = _T("Unicode string"); //use _T() convert const string to wchar_t string

    printf("Convert to wchar_t* from char* using C Runtime library.\n");
    swprintf(unicodeStr, _T("%S"), ansiStr);
    wprintf(_T("Convert from char*, %s\n"), unicodeStr);
}

ANSI-Unicode-8

 


使用建议

上面讲述了Windows Mobile和Wince(Windows Embedded CE)支持那么多字符串,那么我们到底如何选择使用的字符串呢?其实这个没有准则,我下面谈一下我的经验。这不是准则,所以只做参考之用。

一.尽量避免使用char*和wchar_t*

除了以下情况,不得不使用char*和wchar_t*时,大部分时候尽量避免使用char*和wchar_t*。

情况1

做今日组件开发,只是使用Win32,如果不依赖于ATL,WTL,MFC和STL,那么没得选择只能使用char*和wchar_t*。

关于今日组件的开发,可以参考:

关于在Windows Mobile下今日插件使用WTL的问题

 

情况2

封装DLL或者通用静态库提供给第三方使用,例如TinyXML, CppUnitLite这样的类库,他们内部都在char*基础上实现字符串处理类,这样库就不依赖于ATL,WTL,MFC和STL了。

关于TinyXML, CppUnitLite可以参考:

Windows Mobile和Wince下使用TinyXML进行Native C++的开发

Wince和Windows Mobile下native C++的单元测试

Windows Mobile下使用CppUnitLite输出测试结果

 

情况3

封装DLL给.NET Compact Framework使用,接口函数只能使用char*和wchar_t*,不能使用CString和std::string。

关于DLL的封装,可以参考:

Windows Mobile和Wince(Windows Embedded CE)下如何封装Native DLL提供给.NET Compact Framework进行调用

Windows Mobile和Wince(Windows Embedded CE)下封装Native DLL进一步探讨

 

情况4

可以使用char*和wchar_t*包括一些字符串常量,用于替换宏定义。

 

除了上述情况以外,应当尽量避免使用char*和wchar_t*,而是用CString,std::string等封装好的字符串类。

 

二.程序需要同时支持PC和Window Mobile版本时使用CString

如果使用C++加上ATL,WTL或者MFC开发,程序需要同时支持Windows桌面版和Windows Mobile以及Wince,可以考虑使用CString。CString可以很好的兼容ANSI和Unicode版本。

例如我封装的一个SQL Server Compact的数据库访问类,使用到CString,这个类可以支持PC和Windows Mobile。可以参考:

Windows Mobile下Native C++访问SqlCe的封装

 

三.程序需要跨平台时使用std::string

程序不仅仅用于windows平台,而且用于Linux,Unix,BSD等平台,可以考虑使用std::string,我一般不使用std::wstring,觉得没有这个必要,使用std::string在需要的时候转换就可以了。但是如果追求更高的跨平台性,那只能使用char*和wchar_t*了,连STL都不依赖。

 

我个人喜欢使用std::string,因为我大量使用STL。在设计的时候把界面和处理逻辑分开,处理逻辑内部统一使用std::string以及STL的容器。需要界面交互出来,或者调用Win32的时候进行字符串的转换。

 

可以进一步参考的文章

http://www.tenouk.com/ModuleG.html

http://www.codeproject.com/KB/string/cppstringguide1.aspx

作者: Jake LinJake's Blog on 博客园
出处: http://procoder.cnblogs.com

作品Jake Lin创作,采用 知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。 任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请 给我留言
2
0
(请您对文章做出评价)
« 博主上一篇: 在Windows Mobile和Wince(Windows Embedded CE)下进行Win32开发,取出窗口句柄的方法
» 博主下一篇: 如何查看PC和Windows Mobile下蓝牙(Bluetooth)的Stack
« 首页上一篇: ECubeCMS(一个移植到asp.net mvc2 beta平台的Oxite版本)已发布到CodePlex
» 首页下一篇: 用GPU通用并行计算绘制曼德勃罗特集图形 下篇
posted @ 2009-11-25 09:15 Jake Lin 阅读(4436) 评论( 40) 编辑 收藏
  
#1楼 2009-11-25 09:20 joyzml[未注册用户]
沙发
  
#2楼 2009-11-25 09:21 joyzml[未注册用户]
俺来学习啦。支持楼主。
  
#3楼 2009-11-25 09:22 猫咪  
顶一个
  
#4楼 2009-11-25 09:47 YeanJay  
看到关于Windows Mobile的文章,博客园里面不看作者猜猜就你和egmkang的文章了
  
#5楼 2009-11-25 10:12 双霜之君  
牛人啊,顶一个!
  
#6楼 [ 楼主] 2009-11-25 10:34 Jake Lin  
@双霜之君
@YeanJay
@猫咪
@joyzml
谢谢关注。
  
#7楼 [ 楼主] 2009-11-25 10:35 Jake Lin  
@YeanJay
不会呀,在Windows Mobile团队里面还是很多人发文章的。
  
#8楼 2009-11-25 11:00 egmkang  
@YeanJay
汗,我没产量的...学的太慢..
  
#9楼 2009-11-25 11:05 egmkang  
我觉得先讲ANSI C怎么转换字符比较好.
标准C里面有头文件wchar.h,提供了char操作的wchar_t版本,以及转换等.

我最开始是因为项目急,所以才用ATL宏.

个人还是比较看好用使用char和wchar_t,毕竟P/Invoke好弄,另外也比较轻便.
  
#10楼 [ 楼主] 2009-11-25 11:16 Jake Lin  
@egmkang
在“纯C Runtime库转换”有讲纯C的转换方法,我也去看看wchar.h,我个人喜欢用sprintf来转换。
  
#11楼 2009-11-25 11:17 egmkang  
@Jake Lin
恩,感觉sprintf有一点像C#里面的string.Format.
  
#12楼 2009-11-25 11:21 施炯  
呵呵,跟风来顶。
当时我也迷失在类型转换的迷雾中。
  
#13楼 [ 楼主] 2009-11-25 11:22 Jake Lin  
@egmkang
我刚刚看了一下wince里面的wchar.h。好像是字符串操作,没有字符串转换。swprintf放到stdlib.h去了。

wchar.h的定义:
  
#14楼 2009-11-25 11:23 egmkang  
另外C语言中,宽字符是在字符前面加L的,宽字符串是在字符串前面加L,你没讲这个.
而是使用_T()宏.
?
1
2
wchar_t wc=L '\1234' ;
wchar_t * pwc=L "1234" ;
  
#15楼 2009-11-25 11:30 egmkang  
恩,看来是我错了.
stdlib.h下面的...

?
1
2
3
4
#include <stdlib.h>
size_t mbstowcs ( wchar_t * restrict pwcs,
                const char * restrict s,
                size_t n);

?
1
2
3
4
#include <stdlib.h>
size_t wcstombs ( char * restrict s,
                 const wchar_t * restrict pwcs,
                 size_t n);


这个是标准C提供的方式.
  
#16楼 [ 楼主] 2009-11-25 11:40 Jake Lin  
引用 egmkang:
@Jake Lin
恩,感觉sprintf有一点像C#里面的string.Format.

string.Format抄printf的啦,呵呵。
  
#17楼 [ 楼主] 2009-11-25 11:43 Jake Lin  
引用 egmkang:
另外C语言中,宽字符是在字符前面加L的,宽字符串是在字符串前面加L,你没讲这个.
而是使用_T()宏.
?
1
2
wchar_t wc=L '\1234' ;
wchar_t * pwc=L "1234" ;

你说的对L这个作用很大,我现在偏向用_T()来代替L,自动选择字符集。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _T(x)       __TEXT(x)
  
#ifdef  UNICODE                     // r_winnt
  
#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR , * PTCHAR ;
typedef WCHAR TBYTE , * PTBYTE ;
typedef wchar_t _TCHAR;
typedef wchar_t _TSCHAR;
typedef wchar_t _TUCHAR;
typedef wchar_t _TXCHAR;
typedef wint_t _TINT;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
  
typedef LPWSTR LPTCH, PTCH;
typedef LPWSTR PTSTR , LPTSTR ;
typedef LPCWSTR PCTSTR , LPCTSTR ;
typedef LPWSTR LP;
#define __TEXT(quote) L##quote      // r_winnt
  
#else   /* UNICODE */               // r_winnt
  
#ifndef _TCHAR_DEFINED
typedef char TCHAR , * PTCHAR ;
typedef unsigned char TBYTE , * PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
  
typedef LPSTR LPTCH, PTCH;
typedef LPSTR PTSTR , LPTSTR ;
typedef LPCSTR PCTSTR , LPCTSTR ;
#define __TEXT(quote) quote         // r_winnt
  
#endif /* UNICODE */
  
#18楼 2009-11-25 11:46 egmkang  
其实就是根据宏前面加不加L##
  
#19楼 [ 楼主] 2009-11-25 11:47 Jake Lin  
@施炯
谢谢关注。这个问题好像每个初学者都碰到,我现在总结一下,以后碰到,直接拷贝上面的代码用。
  
#20楼 [ 楼主] 2009-11-25 11:49 Jake Lin  
@egmkang
对的,根据预编译宏 UNICODE 来自动判断加不加,但是在wince下,是肯定加的。
  
#21楼 2009-11-25 11:53 李森 - listen  
  
#22楼 [ 楼主] 2009-11-25 11:53 Jake Lin  
引用 egmkang:
恩,看来是我错了.
stdlib.h下面的...

?
1
2
3
4
#include <stdlib.h>
size_t mbstowcs ( wchar_t * restrict pwcs,
                const char * restrict s,
                size_t n);

?
1
2
3
4
#include <stdlib.h>
size_t wcstombs ( char * restrict s,
                 const wchar_t * restrict pwcs,
                 size_t n);


这个是标准C提供的方式.

我又去看了一下你推荐的函数,说实在,我从来没有用过这两个函数,我一直用sprintf,因为sprintf能把任何类型转成字符串,所有一直用。
  
#23楼 2009-11-25 11:56 egmkang  
@Jake Lin
恩STL里面有Stringstream,也是干这一行的.~~
  
#24楼 2009-11-25 12:44 winter-cn  
这个字符集问题在所有的win32环境中都一样 char和wchar_t是C++提供的类型

Win32编程中最好使用Windows类型 包含了windows.h之后 可以使用以下类型 一般有这样的对应关系:
字符 字符串 常量字符串 字符串文字量
TCHAR LPTSTR LPCTSTR TEXT("char") 或者 _T"char"
WCHAR LPWSTR LPCWSTR L"char"
CHAR LPSTR LPCSTR "char"

LP是long ptr的意思 表示长整型指针
C是表示常量的意思
CHAR是字符类型 STR是字符串类型

除非有特别需要 一般都使用T系列的 这可以保证你的字符和字符串总是和API匹配
  
#25楼 [ 楼主] 2009-11-25 16:06 Jake Lin  
@winter-cn
谢谢呀。
  
#26楼 2009-11-25 18:51 minvt  
汗 反响真大
这篇文章真棒 你肯定花了不少功夫呢
  
#27楼 2009-11-26 10:21 minvt  
1 这里
CString
CString最初在MFC里面封装,ATL和WTL分别封装了CString,这三个不同封装的CString具有语义兼容性,也就是他们提供的接口是相同的。使用CString的好处是可以同时兼容ANSI和Unicode,如下例子:

CString str = "Independent String";m_wndPic.SetWindowText(str);m_wndPic是一个CStatic控件,上面的代码不管在ANSI或者在Unicode都能使用,无需更改。


CString str = "Independent 在win32下要改成加_T()的吧?



2 egmkang的回复真有营养 文章配评论更全面呢 另外昨天还遇到一个问题 很有意思 你看看
http://www.devdiv.net/thread-18413-1-1.html


3 最后还有个很重要的方面 网上资料很少 http://www.devdiv.net/thread-18328-1-1.html
注意那个flywhc的回复 他提到了BOM

搞不好可以写一个"字符集"问题进一步探讨啦 哈哈
  
#28楼 2009-11-26 10:24 minvt  
@egmkang
熟人碰面 --

_T()的使用问题确实很重要呢 也不能够完全放心来用 昨天在坛子里就遇到这个问题啦
不知道那个L##是咋实现的 看不懂 --

从回复中也学到很多东西 赞~~
  
#29楼 2009-11-26 10:55 egmkang  
@minvt
L是给编译器看的,说后面的是宽的.
##也是给编译器看的,编译器看见了,就把##前面的和后面的连到一块儿
  
#30楼 2009-11-26 10:59 minvt  
@egmkang
ok 知道了

ge 您可别让俺再去看编译原理啊 哈哈
  
#31楼 [ 楼主] 2009-11-26 12:46 Jake Lin  
引用 minvt:
1 这里
CString
CString最初在MFC里面封装,ATL和WTL分别封装了CString,这三个不同封装的CString具有语义兼容性,也就是他们提供的接口是相同的。使用CString的好处是可以同时兼容ANSI和Unicode,如下例子:

CString str = "Independent String";m_wndPic.SetWindowText(str);m_wndPic是一个CStatic控件,上面的代码不管在ANSI或者在Unicode都能使用,无需更改。


CString str = "Independent 在win32下要改成加_T()的吧?
...

你这么认真,他日必定大有作为。

这个代码是对的,那些代码都经过测试才放上去。
那个地方是CString的=号运算符重载的时候转型。请看下面的代码。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
template <>
class ChTraitsBase< wchar_t >
{
public :
     typedef wchar_t XCHAR;
     typedef LPWSTR PXSTR;
     typedef LPCWSTR PCXSTR;
     typedef char YCHAR;
     typedef LPSTR PYSTR;
     typedef LPCSTR PCYSTR;
};
  
CStringT& operator=( _In_opt_z_ PCYSTR pszSrc )
{
     // nDestLength is in XCHARs
     int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0;
     if ( nDestLength > 0 )
     {
         PXSTR pszBuffer = GetBuffer( nDestLength );
         StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc);
         ReleaseBufferSetLength( nDestLength );
     }
     else
     {
         Empty();
     }
  
     return ( * this );
}
      
  
static void ConvertToBaseType(_Out_cap_(nDestLength) wchar_t * pszDest, int nDestLength,
     _In_count_(nSrcLength) const char * pszSrc, _In_ int nSrcLength = -1) throw ()
{
     // nLen is in wchar_ts
     ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength);
}
  
#32楼 [ 楼主] 2009-11-26 12:48 Jake Lin  
@minvt
@egmkang
##是宏定义里面的,和字符集没有任何关系,用于预编译。
  
#33楼 2009-11-26 14:35 minvt  
@Jake Lin
CString默认会按需转换的啊

可我试了下 在Mobile下不行啊
找个地方放一个临时变量 CString str="ab";
error C2440: “初始化”: 无法从“const char [2]”转换为“ATL::CStringT<BaseType,StringTraits>”
这是什么情况呢?我是在MFC程序下试的
得CString str=_T("ab");这样才行或者加L才行 有点费解
CString又不是系统API 而且是个模板类 不知道咋回事


在CString上按F12可以看到
typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW;
typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA;
typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;


同时兼容ANSI和Unicode是指不要考虑char或者wchar_t么?

我之前的意思是如果"在ANSI或者在Unicode都能使用"
兼容平台的话 那就用_T()可以让CString自动处理是ANSI还是Unicode字符串了吧? 那就不用转了?
  
#34楼 [ 楼主] 2009-11-26 17:26 Jake Lin  
@minvt
CString str;
str = "ab";
或者
CString str("ab");

这样就可以了。


同时兼容ANSI和Unicode是指_T("ab")在ANSI等于 "ab",而在Unicode等于L"ab"。而CString同样道理,在ANSI使用char*作为存储,在Unicode中使用wchar_t*作为存储。

CString str = _T("ab");
在ANSI等于
CString str = "ab";

在Unicode等于
CString str = L"ab";

如果使用了CString str = _T("ab");那么没有字符转换过程(字符转换指char*与wchar_t*的转换)。但是都有=号运算符的重载,分别重载了参数 const char*与 const wchar_t*,还是根据ANSI和Unicode来重载不同的参数。


  
#35楼 2009-11-26 17:38 minvt  
@Jake Lin
ok
原来如此 纠缠了一个多月 现在终于清晰多了
现在使用起来已经顺畅多了
更深入的理解只能以后继续积累了 ^_^
  
#36楼 2009-11-27 20:19 王克伟  
哈哈,好久没来看你的博客了!
  
#37楼 [ 楼主] 2009-11-28 08:24 Jake Lin  
@王克伟
我最近也很忙呀,要找房。
  
#38楼 2010-04-22 15:18 李旭阳  
没系统的学过C++,想做个成型的项目真难!我现在基本上都是吃以前C#的老底,C++里没有多少提高,啥也不想了,努力奋斗!感谢P侠这么棒的博客,让我这个初学者受用匪浅!
  
#39楼 [ 楼主] 2010-04-23 10:10 Jake Lin  
@李旭阳
你过奖了,多交流。
  
#40楼 2193854 2011/9/6 15:36:17 2011-09-06 15:36 李旭阳  
灰常灰常经典的一篇文章,每当我用到C++中的字符转换时,我都会默默的来到这里,嘿嘿。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值