MFC中CString,C++中string,c风格字符串

#1. 标准C中的字符串

**标准C中没有string这样的数据类型,C中的字符串是有char类型的字符数组或者char类型的字符指针来实现的。**例如:

char   name[26]="This is a C-style string"; 或者
char  *name="This is a C-style string"; 

类型的字符串以’\0’为结束标记,所占内存是实际子符长度+1,其初始化和赋值都要逐个字符的赋值,char* 中没有构造函数,仅能由指针赋值,而且是一个极其危险的操作,在声明char * 的时候如果没有赋初值,建议先初始化为NULL,以免出现悬浮指针或者指向地址不明的指针。
标准C中是没有string类型的,但是在标准C中有"string.h"头文件,需要注意的是此“string.h”中的string 非彼string,“string.h”头文件中定义了一些我们经常用到的操作字符串的函数,如复制函数strcpy,连接字符串strcat,比较字符串strcmp,这些函数的操作对象都是指向char *的字符串。

#2. 标准C++中的string类

       C++支持C风格字符串的使用,而且引入了string类的概念,**string为标准模板类STL定义的字符串,几乎可以从所有的字符串构造出来。string字符串类的都文件是"string",并且要和using namespace std; 一起使用。**头文件"string"和头文件"string.h"没有任何关系,前者是标准C++中的模板库类,后者是标准C中的包含常用C字符串处理函数的头文件,如strcmp,前者并非是后者的升级版。
       标准C++中string是一个类, 如在标准C中定义如下:char * pt=NULL; 这无疑是正确的。
       但是在标准C++中定义 string *pt=NULL;这样做编译器不会有警告和错误,但是运行是就会有异常。
       这是因为string作为一个类,定义类的对象时要调用其构造函数的,上面的例子既没有调用其构造函数,还把指针赋值为NULL,很明显就会出错的。正确的 方法是是new操作符,C++中的new不同于C中的malloc, new不但会分配一块内存,还调用类的构造函数。string *pt=new(“this is a c+±style string”); 或者不用指针,这样定义 string str;系统自动调用默认的构造函数,构造一个string类的对象。

#3. MFC中的CString类

       **MFC中的字符串类是CString,封装了string的东西,并增加了一些接口,在功能上完全兼容string类,而一些标准的C/C++不能直接对CString类进行操作,CString 类是微软的visual c++提供的MFC里面的一个类,所以只有支持MFC的工程才可以使用。**如在linux上的工程就不能用CString了,只能用标准C++中的 string类了。另外,因为string类是在c++标准库中,所以它被封装在了std命名空间中,使用之前需要声明using namespace std;而CString类并不在std命名空间中,因为它不是c++的标准库,只是微软的一个封装库。这点看来用string类的程序的移植性更好。

#4. CString 和string的转换

//string-> CString 
string str="ksarea";
CString cstr(str.c_str());//或者CString cstr(str.data());初始化时才行
cstr=str.c_str();或者cstr=str.data();

cstr.format("%s", str.c_str()); //string->CString
cstr.format("%s", str.data()); //string->CString
/*c_str()和data()区别是:前者返回带'/0'的字符串,后者则返回不带'/0'的字符串*/

//CString -> string
str=cstr.GetBuffer(); //CString -> string
cstr.ReleaseBuffer();//释放锁定状态,即cstr可以重新插入数据
/*GetBuffer(0)为一个CString对象重新获取其内部字符缓冲区的指针,返回的LPTSTR为非const的,从而允许直接修改CString中的内容。*/

str = LPCSTR(cstr); //CString->string

#5. CString 和int的转换

int i = 123;
CString cstr;
cstr.format("%d",i);//int->CString 其他的基本类型转化类似
i=atoi(cstr);//CString->int 还有(atof,atol)

#6. CString 和char*的转换

CString cstr = "ksarea";
char* ptemp=cstr.Getbuffer();	//CString->char*
cstr.ReleaseBuffer();

char* str = "lovesha";
CString cstr = str;//char*->CString,而string类型不能直接赋值给CString

       至于int与float、string与char之间的转化可以使用强制转化,或者标准库函数进行。
       对于CString与其他类型的转化方法很多,但其实都殊途同归,朝着一个方向即将类型首先转化为char
类型,因为char是不同类型之间的桥梁。得到char类型,转化为其他类型就非常容易了。
转自

#7. 当使用unicode时CString 转char*需要使用T2A,但要注意如下:

       USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。使用ATL的W2A, A2W, T2A等宏必须使用USES_CONVERSION,在ATL下使用要包含头文件#include “atlconv.h”
       比如我们很常见的问题:在Socket编程时候,我们的IP地址从界面上输进去一般都使用CString类型的,可是在SOCKADDR_IN中的inet_addr却是const char *我们就不能直接用CString来用。我们就可以使用T2A()宏了。

    SOCKADDR_IN localaddr;   
    CString m_IP = L"192.168.1.2";
    USES_CONVERSION;
    localaddr.sin_family = AF_INET;
    localaddr.sin_addr.S_un.S_addr = inet_addr(T2A(m_IP));

       使用USES_CONVERSION需要注意,它是在栈上分配空间的(VC中栈 空间默认2M),主要是因为调用alloca在栈上分配内存,也就是说在使用的函数结束前,不会被释放掉。所有要注意不要在一个函数中用while循环执行它,不然栈空间就马上会分配完,如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。例如:

#include <atlconv.h>
void fun()
{
    while(true)
    {
        {
            USES_CONVERSION;
            DoSomething(A2W("SomeString"));
        }
    }
}

以上问题的解决办法:

      1、自己写字符转换函数

Function that safely converts a 'WCHAR' String to 'LPSTR':
char* ConvertLPWSTRToLPSTR (LPWSTR lpwszStrIn)
{
 	 LPSTR pszOut = NULL;
 	 if (lpwszStrIn != NULL)
  	{
 		int nInputStrLen = wcslen (lpwszStrIn);
		// Double NULL Termination
		int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
 		pszOut = new char [nOutputStrLen];		//使用new分配内存
		if (pszOut)
		{
 	  		memset (pszOut, 0x00, nOutputStrLen);
   			WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
	 	}
  	}
  	return pszOut;
}

上面函数使用new分配内存,返回char*后无法释放,最好自己申请,仅仅调用此函数转换,改写如下:

声明:
void ConvertLPWSTRToLPSTR (LPWSTR lpwszStrIn,  LPSTR lpszOut, int nOutputStrLen  )
{
 	 if (NULL  != lpwszStrIn  && NULL != lpszOut )
  	{
 		int nInputStrLen = wcslen (lpwszStrIn);
 	  	memset (lpszOut, 0x00, nOutputStrLen);
   		WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, lpszOut, nOutputStrLen, 0, 0);
	 	}
  	}
}
使用:
CString cstrTest = "abceffd";
int iTestSize = CStringA(cstrTest).GetLength(); //转换为CStringA用户获取实际占用字节,不管中文2字节,英文1字节
char* chTest = new char[iTestSize];  //自己申请内存
if( NULL == chTest)
{
	AfxMassageBox(_T("内存申请失败"));
}
memset(chTest, 0 , iTestSize);		 //清空
ConvertLPWSTRToLPSTR(cstrTest.GetBuffer(), chTest, iTestSize);
delete[] chTest;					//自己释放内存
chTest = NULL

      2、把字符转换部分放到一个函数中处理。

void fun2()
{
    USES_CONVERSION;
    DoSomething(A2W("SomeString"));
}

void fun()
{
    while(true)
    {
        fun2();
    }
}

     当然,使用 ATL 转换宏,由于不用释放临时空间,所以使用起来非常方便。但是考虑到栈空间的尺寸(VC 默认2M),使用时要注意几点:
1、只适合于进行短字符串的转换;
2、不要试图在一个次数比较多的循环体内进行转换;
3、不要试图对字符型文件内容进行转换,因为文件尺寸一般情况下是比较大的;

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值