1. 程式人生 > >ATL::CStringA和std::string之間轉換的一些誤區

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::CStringAstd::string之間轉換一些誤區

        對於剛做windows下VC的開發同學,型別轉換應該是一個令其很苦惱的問題。我剛寫工作的時候,也為這類問題不停的在網上搜索轉換方法。最近工作中遇到一個“神奇”的bug(一般“神奇”的問題往往是低階錯誤導致的),最後跟蹤發現還是型別轉換問題。(轉載請指明出處) 

ajax的stringjson物件之間轉換

JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。它基於ECMAScript的一個子集。 在AJAX實現前後臺數據互動的時候,通常使用JSON的資料格式,對於JSON來說,有嚴格的程式碼規範,一旦格式出問題,就無法顯示出相應效果,同時還不在控制檯報錯。

javajs中JSONObject,JSONArray,Map,String之間轉換——持續更新中

--------------------------------------------------java中-------------------------------------------------------------- 1.String轉JSONObject

普通字元寬字元之間轉換函式

以下函式會在內部分配記憶體,需要呼叫程式呼叫delete釋放記憶體: namespace _com_util {     // Convert char * to BSTR     //     BSTR __stdcall Con

關於拷貝常規陣列、std::arraystd::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.Datemysql日期之間轉換

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::stringMFC中的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