ATL::CStringA和std::string之间转换的一些误区
? ? ? ? 對于剛做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之间转换的一些误区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 桌面窗口的一些发现
- 下一篇: python3编写简易统计服务器