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之間轉換的一些誤區
對於剛做windows下VC的開發同學,型別轉換應該是一個令其很苦惱的問題。我剛寫工作的時候,也為這類問題不停的在網上搜索轉換方法。最近工作中遇到一個“神奇”的bug(一般“神奇”的問題往往是低階錯誤導致的),最後跟蹤發現還是型別轉換問題。(轉載請指明出處)
ajax的string和json物件之間轉換
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。它基於ECMAScript的一個子集。 在AJAX實現前後臺數據互動的時候,通常使用JSON的資料格式,對於JSON來說,有嚴格的程式碼規範,一旦格式出問題,就無法顯示出相應效果,同時還不在控制檯報錯。
java和js中JSONObject,JSONArray,Map,String之間轉換——持續更新中
--------------------------------------------------java中-------------------------------------------------------------- 1.String轉JSONObject
普通字元和寬字元之間轉換函式
以下函式會在內部分配記憶體,需要呼叫程式呼叫delete釋放記憶體: namespace _com_util { // Convert char * to BSTR // BSTR __stdcall Con
關於拷貝常規陣列、std::array和std::vector速度的一些測試
最近在寫一些有關AI的演算法,需要的一些資料結構要用到複製的操作。因此在這裡測試了一下各種資料的複製速度,編譯器支援C++11/14。 #include <iostream> #includ
JSONObject,JSONArray,Map,String之間轉換
1.String轉JSONObject String jsonMessage = "{\"語文\":\"88\",\"數學\":\"78\",\"計算機\":\"99\"}"; JSONObject myJson = JSONObject.fromObject(json
windows程式設計 Unicode和多位元組之間轉換
Unicode轉多位元組:WideCharToMultiByte 多位元組轉Unicode:MultiByteToWideChar 程式碼演示 #include <windows.h> int WINAPI WinMain( HINSTANCE hInstance,
TCHAR 與 STD::string 之間的若干問題 [轉]
我經常在 C++ 程式中使用標準模板庫(STL)的 std::string 類,但在 使用 Unicode 時碰到了問題。在使用常規 C 風格的字串時,我可以使用 TCHAR 和 _T 巨集,這樣針對 Unicode 或 ASCII 均可以進行編譯,但我 總是發現這種ASC
std::string::find() 和 std::string::npos
int idx = str.find("abc"); if (idx == string::npos) ... 上述程式碼中,idx的型別被定義為int,這是錯誤的,即使定義為 unsigned int 也是錯的,它必須定義為 string::size_type。
Gson在java物件和json字串之間轉換
GsonLib下載連結 Gson相比org.json最大的好處是從json字串轉向java例項時候少了依據每個例項自己賦值的過程,比如在org.json的時候,我們先從json字串構建一個jsonobject,然後用各種的json get方法獲取到每個欄位的值
Python: 在Unicode和普通字串之間轉換
1.1. 問題Problem You need to deal with data that doesn't fit inthe ASCII character set. 你需要處理不適合用ASCII字符集表示的資料. 1.2. 解決Solution Unicode
java.util.Date和mysql日期之間轉換
Pojo裡面用的是java.util.Date;MYSQL裡面用的是datetime。因為表單提交所有資料都是以字串的形式傳輸(如果說錯請大神指正),所以在後臺接收到前臺傳來的日期字串是要轉換一下。 /** * 字串轉換成日期 * @param str * @ret
基本型別資料和包裝類之間轉換
1、可以通過對應的包裝類的建構函式完成。1、包裝類中提供的靜態函式:事例:packageTest;publicclass DoubleDemo {publicstaticvoid main(String[] args) {//定義一個double型別的資料double d=1
int double std:string之間的互轉
1 /*2 (C) OOMusou 2008 http://oomusou.cnblogs.com3 4 Filename : string_to_double.cpp5 Compiler : Visual C++ 9.0 / Visual Studio 20086 Description : D
迭代器和下標之間轉換
轉換主要是使用stl中的advance和distance函式來進行的, advance是將iterator移動指定個元素,distance是計算兩個iterator直接的距離。 distance計算第一個引數到第二個引數之間的距離。如果第二個引數的順序在第一個引數前面的話,
常用時間處理方法:時間戳和格式化時間之間轉換;時間比大小
1、獲取當前格式化時間: // 獲取當前時間的時間戳,並轉換成格式化時間 long getNowTimeLong = System.currentTimeMillis(); //轉換成12小時進位制 SimpleDateFormat fromatTi
完成一程式演示字元陣列、C風格字串、std::string和MFC中的Cstring型別之間的相互轉換
《C++標準函式庫》中說的有三個函式可以將字串的內容轉換為字元陣列和C—string1.data(),返回沒有”\0“的字串陣列2,c_str(),返回有”\0“的字串陣列3,copy().............................................................
30-python3 中 bytes 和 string 之間的互相轉換
轉自:http://www.jb51.net/article/105064.htm password = b'123456' 等價於: pw = '123456' password = pw.encode(encoding='utf-8') 前言
c++中string類物件和字元陣列之間的相互轉換
string類在c++中是一個模板類,位於名字空間std中,注意這裡不是string.h,string.h是C字串標頭檔案。 將string型別轉換為字元陣列char arr[10];string s("ABCDEFG");int len = s.copy(arr,&nb
Solidify實現一個智慧合約9(陣列和string之間的轉換關係)
固定大小位元組陣列之間的轉換 固定大小位元組陣列,我們可以通過bytes1~32來進行宣告,固定大小位元組陣列的長度不可變,內容不可修改。 pragma solidity ^0.4.4; contr