MFC字符串类型

MFC支持有很多种字符和字符串数据类型,在此将他们整理一下以便记忆。

  1. char wchar_t
    char 这个不用说了是标准c的字符类型,8bit

wchar_t 用来保存UNICODE字符集的类型,16bit

  1. CHAR WCHAR TCHAR
    CHAR 与小写的char等价
    typedef char CHAR;

WCHAR 也可以认为它与wchar_t等价
#ifndef _MAC
typedef wchar_t WCHAR;
#else
typedef unsigned short WCHAR;
#endif

  1. LPSTR LPWSTR LPCSTR LPCWSTR
    LPSRT 等价于char*
    typedef CHAR *LPSTR;

LPWSRT 等价于wchar_t*
typedef WCHAR *LPWSTR;

LPCSRT 等价于const char*
typedef CONST CHAR *LPCSTR;

LPCWSRT 等价于const wchar_t*
typedef CONST WCHAR *LPCWSTR;

  1. TCHAR LPTSTR LPCTSTR
    TCHAR 在非UNICODE环境下,它等价于char;在UNICODE环境下,它等价于wchar_t
    #ifdef UNICODE
    typedef WCHAR TCHAR;
    #else
    typedef char TCHAR;
    #endif

LPTSTR 在非UNICODE环境下,它等价于char*;在UNICODE环境下,它等价于wchar_t*
#ifdef UNICODE
typedef LPWSTR LPTSTR;
#else
typedef LPSTR LPTSTR;
#endif

LPCTSTR 在非UNICODE环境下,它等价于const char*;在UNICODE环境下,它等价于const wchar_t*
#ifdef UNICODE
typedef LPCWSTR LPCTSTR;
#else
typedef LPCSTR LPCTSTR;
#endif

  1. string CString
    string 是C++标准的字符串类,定义在STL中
    typedef basic_string<char, char_traits, allocator > string;

CString 是Visual C++中最常用的字符串类,继承自CSimpleStringT类,主要应用在MFC和ATL编程中。
typedef CStringT<TCHAR, StrTraitMFC> CString;

  1. 常用函数的char版本和wchar_t版本
    size_t strlen( const char *string );
    size_t wcslen( const wchar_t *string );

char *strcpy( char *strDestination, const char *strSource );
wchar_t *wcscpy( wchar_t *strDestination, const wchar_t *strSource );

char *strcat( char *strDestination, const char *strSource );
wchar_t *wcscat( wchar_t *strDestination, const wchar_t *strSource );

int strcmp( const char *string1, const char *string2 );
int wcscmp( const wchar_t *string1, const wchar_t *string2 );

CString 与Char *的转换:

有两方法LPCTSTR和GetBuffer()
看看这个

LPCTSTR 与 GetBuffer(int nMinBufLength)
这两个函数提供了与标准C的兼容转换。在实际中使用频率很高,但却是最容易出错的地方。这两个函数实际上返回的都是指针,但它们有何区别呢?以及调用它们后,幕后是做了怎样的处理过程呢?
(1) LPCTSTR 它的执行过程其实很简单,只是返回引用内存块的串地址。 它是作为操作符重载提供的,
所以在代码中有时可以隐式转换,而有时却需强制转制。如:
CString str;
const char* p = (LPCTSTR)str;
//假设有这样的一个函数,Test(const char* p); 你就可以这样调用
Test(str);//这里会隐式转换为LPCTSTR
(2) GetBuffer(int nMinBufLength) 它类似,也会返回一个指针,不过它有点差别,返回的是LPTSTR
(3) 这两者到底有何不同呢?我想告诉大家,其本质上完全不一样,一般说LPCTSTR转换后只应该当常量使用,或者做函数的入参;而GetBuffer(…)取出指针后,可以通过这个指针来修改里面的内容,或者做函数的入参。为什么呢?也许经常有这样的代码:
CString str(“abcd”);
char* p = (char*)(const char*)str;
p[2] = ‘z’;
其实,也许有这样的代码后,你的程序并没有错,而且程序也运行得挺好。但它却是非常危险的。再看
CString str(“abcd”);
CString test = str;

char* p = (char*)(const char*)str;
p[2] = ‘z’;
strcpy(p, “akfjaksjfakfakfakj”);//这下完蛋了
你知道此时,test中的值是多少吗?答案是"abzd".它也跟着改变了,这不是你所期望发生的。但为什么会这样呢?你稍微想想就会明白,前面说过,因为CString是指向引用块的,str与test指向同一块地方,当你p[2]='z’后,当然test也会随着改变。所以用它做LPCTSTR做转换后,你只能去读这块数据,千万别去改变它的内容。

假如我想直接通过指针去修改数据的话,那怎样办呢?就是用GetBuffer(…).看下述代码:
CString str(“abcd”);
CString test = str;

char* p = str.GetBuffer(20);
p[2] = ‘z’; // 执行到此,现在test中值却仍是"abcd"
strcpy(p, “akfjaksjfakfakfakj”); // 执行到此,现在test中值还是"abcd"
为什么会这样?其实GetBuffer(20)调用时,它实际上另外建立了一块新内块存,并分配20字节长度的buffer,而原来的内存块引用计数也相应减1. 所以执行代码后str与test是指向了两块不同的地方,所以相安无事。
(4) 不过这里还有一点注意事项:就是str.GetBuffer(20)后,str的分配长度为20,即指针p它所指向的buffer只有20字节长,给它赋值时,切不可超过,否则灾难离你不远了;如果指定长度小于原来串长度,如GetBuffer(1),实际上它会分配4个字节长度(即原来串长度);另外,当调用GetBuffer(…)后并改变其内容,一定要记得调用ReleaseBuffer(),这个函数会根据串内容来更新引用内存块的头部信息。
(5) 最后还有一注意事项,看下述代码:
char* p = NULL;
const char* q = NULL;
{
CString str = “abcd”;
q = (LPCTSTR)str;
p = str.GetBuffer(20);
AfxMessageBox(q);// 合法的
strcpy(p, “this is test”);//合法的,
}
AfxMessageBox(q);// 非法的,可能完蛋
strcpy(p, “this is test”);//非法的,可能完蛋
这里要说的就是,当返回这些指针后, 如果CString对象生命结束,这些指针也相应无效。
3 拷贝 & 赋值 & “引用内存块” 什么时候释放?

下面演示一段代码执行过程
void Test()
{
CString str(“abcd”);//str指向一引用内存块(引用内存块的引用计数为1,
长度为4,分配长度为4)
CString a;//a指向一初始数据状态,
a = str; //a与str指向同一引用内存块(引用内存块的引用计数为2,
长度为4,分配长度为4)
CString b(a);//a、b与str指向同一引用内存块(引用内存块的引用
计数为3,长度为4,分配长度为4)
{
LPCTSTR temp = (LPCTSTR)a;//temp指向引用内存块的串首地址。
(引用内存块的引用计数为3,长度为4,分配长度为4)
CString d = a; //a、b、d与str指向同一引用内存块(引用内存块的引用计数为4, 长度为4,分配长度为4)
b = “testa”; //这条语句实际是调用CString::operator=(CString&)函数。
b指向一新分配的引用内存块。(新分配的引用内存块的
引用计数为1,长度为5,分配长度为5)
//同时原引用内存块引用计数减1. a、d与str仍指向原
引用内存块(引用内存块的引用计数为3,长度为4,分配长度为4)
}//由于d生命结束,调用析构函数,导至引用计数减1(引用内存
块的引用计数为2,长度为4,分配长度为4)
LPTSTR temp = a.GetBuffer(10);//此语句也会导致重新分配新内存块。
temp指向新分配引用内存块的串首地址(新
分配的引用内存块的引用计数为1,长度
为0,分配长度为10)
//同时原引用内存块引用计数减1. 只有str仍
指向原引用内存块(引用内存块的引用计数为1,
长度为4,分配长度为4)
strcpy(temp, “temp”); //a指向的引用内存块的引用计数为1,长度为0,分配长度为10
a.ReleaseBuffer();//注意:a指向的引用内存块的引用计数为1,长度为4,分配长度为10
}
//执行到此,所有的局部变量生命周期都已结束。对象str a b 各自调用自己的析构构
//函数,所指向的引用内存块也相应减1
//注意,str a b 所分别指向的引用内存块的计数均为0,这导致所分配的内存块释放
通过观察上面执行过程,我们会发现CString虽然可以多个对象指向同一引用内块存,但是它们在进行各种拷贝、赋值及改变串内容时,它的处理是很智能并且非常安全的,完全做到了互不干涉、互不影响。当然必须要求你的代码使用正确恰当,特别是实际使用中会有更复杂的情况,如做函数参数、引用、及有时需保存到CStringList当中,如果哪怕有一小块地方使用不当,其结果也会导致发生不可预知的错误

转载自:https://blog.csdn.net/enjolras/article/details/6024698

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值