对于刚做windows下VC的开发同学,类型转换应该是一个令其很苦恼的问题。我刚写工作的时候,也为这类问题不停的在网上搜索转换方法。最近工作中遇到一个“神奇”的bug(一般“神奇”的问题往往是低级错误导致的),最后跟踪发现还是类型转换问题。(转载请指明出处)

ATL::CStringA和std::string都可以“接受”\0,也就是说,在CStringA的对象的内容和std::string类型数据中可以包含多个\0,而不是最后一位是\0,。这个可能是很多人对它们认识的一个误区。

贴一下测试的相关代码

// string.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include <string>std::string RetCommonString()
{std::string str = "ABCDE\0FGH";return str;
}std::string RetBreakString()
{std::string str = "";char charrayp[9];charrayp[0] = 'A';charrayp[1] = 'B';charrayp[2] = 'C';charrayp[3] = 'D';charrayp[4] = 'E';charrayp[5] = '\0';charrayp[6] = 'F';charrayp[7] = 'G';charrayp[8] = 'H';str.append( charrayp, 9);return str;
}ATL::CStringA RetCommonCStringA()
{ATL::CStringA strA = "ABCDE\0FGH";return strA;
}ATL::CStringA RetBreakCStringA()
{ATL::CStringA strA = "";char charrayp[9];charrayp[0] = 'A';charrayp[1] = 'B';charrayp[2] = 'C';charrayp[3] = 'D';charrayp[4] = 'E';charrayp[5] = '\0';charrayp[6] = 'F';charrayp[7] = 'G';charrayp[8] = 'H';LPSTR lpTmp = strA.GetBuffer(9);if ( NULL !=  lpTmp ){memcpy( (void*)lpTmp, charrayp, 9 );}strA.ReleaseBuffer(9);return strA;
}int _tmain(int argc, _TCHAR* argv[])
{ATL::CStringA strCommonCStringA = RetCommonCStringA();ATL::CStringA strBreakCStringA = RetBreakCStringA();void* pstrCommonCStringA = &strCommonCStringA;void* pstrBreakCStringA = &strBreakCStringA;std::string strCommonString = RetCommonString();std::string strBreakString = RetBreakString();void* pstrCommonString = &strCommonString;void* pstrBreakString = &strBreakString;{int nstrBreakCStringA = strBreakCStringA.GetLength();int nstrCommonCStringA = strCommonCStringA.GetLength();if ( nstrBreakCStringA == nstrCommonCStringA ){// 这儿不会相等ATLASSERT(FALSE);}std::string::size_type lstrBreakStringLength = strBreakString.length();std::string::size_type lstrCommonStringLength = strCommonString.length();if ( lstrCommonStringLength ==  lstrBreakStringLength ){// 这儿不会相等ATLASSERT(FALSE);}}// std::string转CStringA的正确方法,但存在长度限制{std::string::size_type lstringlength = strBreakString.length();ATL::CStringA CStringAobj = "";LPSTR lpCStringAobj = CStringAobj.GetBuffer( (int)lstringlength );memcpy( (void*) lpCStringAobj, strBreakString.c_str(), lstringlength );CStringAobj.ReleaseBuffer((int)lstringlength);std::string::size_type lstrBreakStringLength = strBreakString.length();int nCStringobj = CStringAobj.GetLength();if ( lstrBreakStringLength != nCStringobj ){ATLASSERT(FALSE);}// 内容就不比较了,直接在调试时看内存}// std::string转CStringA的错误方法{// ERROR: CStringAObj = stringobj.c_str(){ATL::CStringA CStringAobj = strBreakString.c_str();std::string::size_type lstrBreakStringLength = strBreakString.length();int nCStringobj = CStringAobj.GetLength();if ( lstrBreakStringLength != nCStringobj ){ATLASSERT(FALSE);}}// ERROR: CStringobj = CStringA( stringobj.c_str() );{ATL::CStringA CStringAobj( strBreakString.c_str() ) ;std::string::size_type lstrBreakStringLength = strBreakString.length();int nCStringobj = CStringAobj.GetLength();if ( lstrBreakStringLength != nCStringobj ){ATLASSERT(FALSE);}}// ERROR: CStringAobj.Format( "%s", stringobj.c_str() );{ATL::CStringA CStringAobj;CStringAobj.Format( "%s", strBreakString.c_str() );std::string::size_type lstrBreakStringLength = strBreakString.length();int nCStringobj = CStringAobj.GetLength();if ( lstrBreakStringLength != nCStringobj ){ATLASSERT(FALSE);}}}// CStringA转std::string的正确方法{int nstrBreakCStringALength = strBreakCStringA.GetLength();LPSTR lpstrBreakCStringA = strBreakCStringA.GetBuffer( nstrBreakCStringALength );strBreakCStringA.ReleaseBuffer( nstrBreakCStringALength );std::string strobj = "";strobj.append( lpstrBreakCStringA, nstrBreakCStringALength );std::string::size_type lstrobjLength = strobj.length();int nCStringobj = strBreakCStringA.GetLength();if ( lstrobjLength != nCStringobj ){ATLASSERT(FALSE);}}// ERROR: stringobj = CStringAObj{std::string strobj = strBreakCStringA;std::string::size_type lstrobjLength = strobj.length();int nCStringobj = strBreakCStringA.GetLength();if ( lstrobjLength != nCStringobj ){ATLASSERT(FALSE);}}return 0;
}

调试这个程序,我们查看一下相关内存。

std::string类型数据strBreakString(内容为"ABCDE\0FGH") 的在内存中的数据如下图

红线标志的09就是这个strBreakString的长度。

std::string类型数据strCommonString(内容为"ABCDE") 的在内存中的数据如下图

红线标志的05就是这个strCommonString的长度。

查看一下strBreakString和strCommonString的来源,可以看出,给std::string类型数据用=赋值,如果内容中包含\0,则std::string类型数据只能接受\0之前的数据。所以strCommonString的数据只有\0之前的ABCDE。而使用std::string的append方法,将会将\0也赋值进去。

我们再看一下ATL::CStringA对象在内存中的数据形式。

ATL::CStringA类型数据strBreakCStringA (内容为"ABCDE\0FGH") 的在内存中的数据如下图

红线标志的09就是这个strBreakCStringA 的长度。

ATL::CStringA类型数据strCommonCStringA (内容为"ABCDE") 的在内存中的数据如下图

红线标志的05就是这个strCommonCStringA 的长度。

查看一下strBreakCStringA 和strCommonCStringA 的来源,可以看出,给ATL::CStringA类型数据用=赋值,如果内容中包含\0,则ATL::CStringA类型数据只能接受\0之前的数据。所以strCommonCStringA 的数据只有\0之前的ABCDE。而使用ATL::CStringA的GetBuffer、ReleaseBuffer等方法,再加上memcpy,可以将\0也赋值进去。

如果方便,可以调试一下这个例子。可以发现网上一些std::string和ATL::CStringA之间的转换方法存在错误。如:网上有些方法是CStringAObj = stringobj.c_str(),或者CStringAobj.Format( "%s", stringobj.c_str() ),这些方法都会导致ATL::CStringA对象的内容可能被std::string中的存在的\0截断。而正确的方法大致如下框架

{std::string::size_type lstringlength = strBreakString.length();ATL::CStringA CStringAobj = "";LPSTR lpCStringAobj = CStringAobj.GetBuffer( (int)lstringlength );memcpy( (void*) lpCStringAobj, strBreakString.c_str(), lstringlength );CStringAobj.ReleaseBuffer((int)lstringlength);std::string::size_type lstrBreakStringLength = strBreakString.length();int nCStringobj = CStringAobj.GetLength();if ( lstrBreakStringLength != nCStringobj ){ATLASSERT(FALSE);}// 内容就不比较了,直接在调试时看内存}

(转载请指明出处)

ATL::CStringA和std::string之间转换的一些误区相关推荐

  1. char[],char *,string之间转换

    char []与char *之间转换 char []转char *:直接进行赋值即可 // char[] 转char * char str[] = "lala"; char *st ...

  2. C++ 中 char[],char *,string之间转换

    char []与char *之间转换 char []转char *:直接进行赋值即可 // char[] 转char * char str[] = "lala"; char *st ...

  3. [转] HTML5 Blob与ArrayBuffer、TypeArray和字符串String之间转换

    1.将String字符串转换成Blob对象 //将字符串 转换成 Blob 对象 var blob = new Blob(["Hello World!"], {type: 'tex ...

  4. std::string int 转换

    c++     std::string test("11);     int startid = std::stoi(test);      注意:test 为空,则会抛出异常     st ...

  5. 对象和String之间转换(包含基本类型转换)

    开发过程中,一般将对象转换成String 或String 转对象 大部分通过fastjson的方式,但是各种json框架在处理基本类型的时候,会显得力不从心.这里最优秀的还是jackson的转换方式. ...

  6. QT在使用protocal的问题解决记录之std :: string和QByteArray之间的无损转换

    服务器端使用的是skynet+lua,lua版本是5.3.5,pbc库是前面的教程中编译的. 客户端使用是C++版本的protobuf,也是教程里编译的. 客户端使用的是Qt库QTcpSocket收网 ...

  7. string和wstring之间转换的三种方法

    方法1 #include <string> #include <locale> #include <codecvt>//convert string to wstr ...

  8. c++中几种常见的类型转换。int与string的转换,float与string的转换以及string和long类型之间的相互转换。to_string函数的实现和应用。...

    1.string转换为int a.采用标准库中atoi函数,对于float和龙类型也都有相应的标准库函数,比如浮点型atof(),long型atol(). 他的主要功能是将一个字符串转化为一个数字,在 ...

  9. python str byte编码_Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题...

    Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分.文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示.Python 3不会以任意隐式的方式混用str ...

最新文章

  1. Oracle数据库相关命令
  2. Python中import导入上一级目录模块及循环import问题的解决
  3. 第一篇:数据库服务概述
  4. 提权 调试权限 OpenProcess 拒绝访问的解决办法
  5. C++语言基本概念(5)
  6. 新装机器如何修改IP地址
  7. HTTP/2 学习笔记
  8. golang json数组拼接
  9. Silverlight4.0教程之WebBrowser控件(Silverlight内置HTML浏览器控件)
  10. 解决 SSH Connection closed by foreign host 问题
  11. Google code jam 2008, Qualification Round:Save the Universe, 翻译
  12. nyoj 86 找球号(一)
  13. php 工厂模式作用,PHP工厂模式的好处概述
  14. WIN10如何管理开机启动项?
  15. 网站服务器的宽带是1mb是什么意思,1mb/s网速是什么意思
  16. 只要干不死,就往死里干
  17. Java内存中神奇的64MB
  18. 雷达的工作原理示意图_雷达的工作原理是什么
  19. Python自然语言处理实战(1):NLP基础
  20. mysql 的数据库引擎

热门文章

  1. STM32 GPIO的原理、特性、选型和配置
  2. CS131专题-3:图像梯度、边缘检测(sobel、canny等)
  3. HDU - 5875 2016 ACM/ICPC 大连网络赛 H题 暴力
  4. OpenCV(二)逐像素的图像复制、图像边缘检测(自实现和API实现)
  5. 数据结构与算法(2-1)线性表之顺序存储(顺序表)
  6. 【深度学习理论】(2) 卷积神经网络
  7. c+语言+null,C/C++语言中NULL、'\0’和0的区别
  8. Qt创建多线程的步骤
  9. 深入浅出的讲解傅里叶变换(完整)
  10. 【一个诡异的问题】用饿了么的自定义主题之后发现表格顶部的复选框checkbox错位了