当前位置: 代码迷 >> 综合 >> CString、string和char之间的类型转换
  详细解决方案

CString、string和char之间的类型转换

热度:61   发布时间:2023-12-12 04:56:34.0

文章目录

        • 0. 题外话
        • 1. 前言
        • 2. 类型转化
          • 2.1 CString和string的相互转化
          • 2.2 CString和char*的相互转化
          • 2.3 char*和string的相互转化
        • 3. 总结
        • 4. 使用总结

0. 题外话

由于最近完成一个工程时候总是涉及到类型转换,然后总是出现转换后编译出错或者中文乱码情况,内心有点崩溃,所以就出了这个总结~希望以后遇到类型转换这块就比较熟练啦~

1. 前言

首先要意识到一点:CString、string、char*和char[]是不同玩意儿~

特别的是string和char*不能直接转的!

1)char*和char[]的区别

可能需要的一些小知识:
数据在内存中的存储区域 
*栈:就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 
*堆:就是那些由new或malloc分配的内存块,在不适用时,要手动用delete或free来释放内存区域。
*全局/静态存储区:全局变量和静态变量被分配到同一块内存中,他们共同占用同一块内存区。 
*常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多) 

如果用字符串直接对char*赋值,那么相当于该char*类型指针指向一个常量字符串,分配的内存为常量存储区,所以不允许修改。

但如果用字符串对char[]赋值,那么其分配的内存为栈,所以可以修改。如果用char[]类型的变量赋值给char*,那么此时char*指向的内存为栈,所以可以修改。

2)char和string的区别

在C++中,string有两种,一种是字符串char[],另外一种是封装好的字符串类,要区别理解。例如’a’是char, "a"是char string,这两者都是普通的字符和字符串,和C语言中没什么不同值得注意的是后者包含两个字符,末尾有一个隐身的’\0’
而 string str = “a” 是C++ 封装好的string。C++中的char string和string不是一回事。

当用到了"string"这个关键词,就不是普通的字符串,而是用到了封装后的类。

在C++中,char仍然是一个primitive type(原始类型),而string已经经过封装,成为了一个class(类)用到它时,我们需要 #include <string>,它是C++ Standard Library (C++标准库)的一部分。

3)CString和string的区别

CString是属于MFC的类,因此一些标准C/C++库函数是不能对CString类型操作,so需要将CString类型转化为char*等其他数据类型的情况。

首先要明确,标准C中是不存在string类型的,string是标准C++扩充字符串操作的一个类。
但是我们知道标准C中有string.h这个头文件,这里要区分清楚,此string非彼string。
string.h这个头文件中定义了一些我们经常用到的操作字符串的函数,如:strcpy、strcat、strcmp等等,但是这些函数的操作对象都是char*指向的字符串。
而C++的string类操作对象是string类型字符串,该类重装了一些运算符,添加了一些字符串操作成员函数,使得操作字符串更加方便。
有的时候我们要将string串和char*串配合使用,所以也会涉及到这两个类型的转化问题。原文:https://blog.csdn.net/bitxinhai/article/details/2292014 

2. 类型转化

2.1 CString和string的相互转化

1)string 转 CString

string str = "testString";
// 方式一
CString cstr(str.c_str());
// 或CString cstr(str.data());// 方式二
cstr = str.c_str();
// 或cstr = str.data()// 方式三 这种输出结果会乱码 原因有待研究
// cstr.Format(L"%s", str.c_str());
// 或cstr.Format(L"%s", str.data());// 方式三
// 包含头文件atlconv.h
cstr = CA2W(str.c_str(), CodePage);

PS:c_str()和data()的区别:前者返回带/0的字符串,后者返回不带/0的字符串

总结:先调用string的c_str()方法,然后再转化为CString。

2)CString 转 string

string str;
CString cstr = L"test中文";
// 方式一 编译出错,这种情况下转换得到的结果是wstring,因为这时候的cstr是宽字符
str = cstr.GetBuffer();
str = cstr.ReleaseBuffer();// 方式二 编译出错,这种情况下转换得到的结果也是wstring,因为这时候的cstr是宽字符
str = LPCTSTR(cstr);// PS:若想将wstring转为string,那么可以使用WidecharToMutiChar这个函数进行转化// 方式三 编译正确,这时可以把宽字符的cstr转化为string
// 包含头文件atlconv.h
str = CW2A(cstr.GetBuffer(), CodePage);

CodePage的取值

PS:调用ReleaseBuffer原因

不给 GetBuffer 传递参数时它使用默认值 0,意思是:“给我这个字符串的指针,我保证不加长它”。假设你想增加字符串的长度,就必须将你需要的字符空间大小(注意:是字符而不是字节,因为 CString 是以隐含方式感知 Unicode 的)传给它。当调用 ReleaseBuffer 时,字符串的实际长度会被重新计算,然后存入 CString 对象中。
必须强调一点,在 GetBuffer 和 ReleaseBuffer 之间这个范围,一定不能使用你要操作的这个缓冲的 CString 对象的任何方法。因为 ReleaseBuffer 被调用之前,该 CString 对象的完整性得不到保障。原文:https://blog.csdn.net/yysdsyl/article/details/2463662 
2.2 CString和char*的相互转化

1)CString转char*

CString cstr = L"testCstr哈哈";
// 编译不过,此时转换的也是wchar_t*
char* pszTmp = cstr.GetBuffer();char* pszTmp = NULL;
// 这种情况下编出来的是中文乱码
strcpy(pszTmp, CW2A(cstr, CP_UTF8));
// 这种情况下编出来的中文不乱码
strcpy(pszTmp, CW2A(cstr, CP_ACP));
// 我理解可能是因为待转换的字符集是属于ANSI CODE的,而不是UTF-8 Code。所以CP_ACP转换后中文不乱码

2)char*转CString

char* pszTmp = "testChar*";
CString cstr;
// 这种方式传过去也是乱码了
cstr.Format(L"%s", pszTmp);
// 这种方式传过去没有乱码
cstr = CA2W(pszTmp, CP_ACP);
2.3 char*和string的相互转化

1)char*转string

char* pszTmp = "testChar*";
string str(pszTmp);

2)string转char*

string str = "testString";
// 因为c_str()返回结果是const char*类型,所以得再类型转换一次
// 这样编译才过
char*  pszTmp = (char*)str.c_str();

PS:附带string的构造函数

string();string (const string& str);string (const string& str, size_t pos, size_t len = npos);string (const char* s);string (const char* s, size_t n);string (size_t n, char c);template <class InputIterator>  string  (InputIterator first, InputIterator last);string (initializer_list<char> il);string (string&& str) noexcept;

3. 总结

1)至于int与float、string与char之间的转化可以使用强制转化,或者标准库函数进行。

2)对于CString与其他类型的转化方法很多,但其实都殊途同归,朝着一个方向即将类型首先转化为char*类型,因为char*是不同类型之间的桥梁。

3)得到char*类型,转化为其他类型就非常容易了。

4. 使用总结

CString宽字符转为String多字节字符还是用CA2W或CW2A比较方便,但是这两个函数是在栈上分配内存的,如果是在循环内使用,已经要在这行加个花括号,在语句块里面调用,这样才不会栈溢出。

一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。
visual studio修改路径为:Project->Propertites->C/C++->Link->System

,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:
打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。
visual studio修改路径为:
Project->Propertites->C/C+±>Link->System

PS:如果这篇文章对你有用的话,可以点个赞哟~
PPS:如果这篇文章中有不对的地方,欢迎指正呀~
Thanks~(?ω?)

参考文章:

  1. https://blog.csdn.net/bitxinhai/article/details/2292014
  2. https://blog.csdn.net/yysdsyl/article/details/2463662
  相关解决方案