問題:數組
BSTR a = _bstr_t("a");ide
BSTR b = _bstr_t("b"); 函數
CString c ; 測試
c = a; 指針
MessageBox(c); code
c = b; 對象
MessageBox(c); 內存
爲何消息框中顯示的都是 b? 字符串
若是這樣: 編譯器
_bstr_t bstr1("a");
BSTR a = bstr1;
_bstr_t bstr2("b");
BSTR b = bstr2;
CString c ;
c = a;
MessageBox(c);
c = b;
MessageBox(c);
消息框中顯示就對了!
Answer:
首先要明確,_bstr_t是對BSTR的封裝。
Code 1:
BSTR a = _bstr_t("a");
//這裏,_bstr_t("a")只是臨時對象,當它初始化(包含一個內部的BSTR)並賦值給BSTR a以後,它就被撤銷了。而它賦的值是BSTR的地址。
BSTR b = _bstr_t("b");
//第二次,仍然產生一個臨時對象,它也初始化...過程跟上面同樣。並且,因爲前面的_bstr_t對象已被撤銷,因此它產生BSTR的地址也同上。
//因此,實際上a,b指向同一個地址。而該地址的內容被寫了兩次。
Code 2:
_bstr_t bstr1("a");
BSTR a = bstr1;
_bstr_t bstr2("b");
BSTR b = bstr2;
//這裏的兩個_bstr_t bstr1,bstr2都是局部對象,同時存在。因此,他們內部包含的BSTR的地址不同。這樣分別賦值就沒問題。
#if defined(WIN32) && !defined(OLE2ANSI)
typedef WCHAR OLECHAR;
#else
typedef char OLECHAR;
#endif
typedef OLECHAR* BSTR;
實際上BSTR就是直接指向字符串的首地址(雙字節或者ANSI字符串)。
而BSTR以前的四個字節是該字符串的長度,由編譯器生成的代碼自動去讀這個長度,而不是用"\0"來標識字符串的結束。
BSTR字符串有如下幾個要點要強調一下:
1.一個BSTR字符串變量其實是一個指針變量。它佔用32bit即4個字節,就像其它的指針同樣。並且,它指向一個Unicode格式的字符數組。可是,咱們不能把字符串與BSTR字符串等同起來。咱們必須用它本身確切的名字――「BSTR「。
2.一個BSTR字符串變量指向的字符串數組必須由4個字節的保留字開始(保存字符串數組的字節數而不是字符數),由2個空字符結束。
3.因爲空字符在Unicode格式的字符串中的任何位置都有可能出現,因此,以空字符聲明一個Unicode格式的字符串的結束並不合適。所以,在4個保留字中保存字符串的長度是相當重要的。
4.咱們再強調一下,BSTR字符串指針實際指向的是Unicode格式的字符數組的首地址,而不是開頭的4個字節。接下來咱們就會看到,在這兒這樣不厭其煩地強調BSTR字符串變量的特徵是爲了與立刻就要解釋的VC++中的string類型做個比較。
5.前4個字節的length記錄的是字符數組的字節數(注意,不是字符數),包括結尾的空字節。由於數組是Unicode格式的,因此實際字符是length的一半。
在這兒強調一下,一個Unicode格式的空字符實際上是佔用2個字節的空間,而不是1個字節。在Unicode格式的數組中測試空字符時要小心這一點。
咱們通常在慣例上說BSTR字符串「help」是「一個BSTR類型的字符串」。通常公認爲,一個BSTR字符串變量指向的一個字符數組中包括至少兩個空字符。
就Visual Basic來講,BSTR字符串未尾的兩個空字節可能沒什麼用處,可是對Win32來講,它們倒是相當重要的。緣由在於,Win32版本的Unicode String(它稱爲LPWSTR)定義爲指向一個空字符結尾的Unicode格式的字符串的指針。
從這個緣由上解釋BSTR字符串爲何要以空字符結尾就合情合理了。下面讓咱們討論一下C++類型的string變量。
兩句代碼:
Dim str as String
str=」help」
str表示的是一個BSTR字符串變量的名字,而不是一個Unicode格式的字符數組。換句話說,str是一個保存地址xxxx的變量的名字。
如下是個小小的實驗,它代表Visual Basic中string變量是指向字符數組的指針而不是字符數組。下面定義了一個結構,它的成員變量的類型是string。
Private Tyep utTest
astring As String
bstring As String
End Type
Dim uTest As utTest
Dim s as String
s=」testing」
uTest.astring=」testing」
uTest.astring=」testing」
Debug.Print Len(s)
Debug.Print Len(uTest)
這幾句代碼的執行結果是:
7
8
對string變量來講,Len函數返回的是字符串數組的字符個數。因此7個字符的字符串「testing」返回7。對結構變量uTest來講,Len函數返回的是該結構佔用的內存空間。因此返回值8清楚地代表了每個BSTR變量在內存中佔用4個字節。由於BSTR是一個Win32的指針!
C類型的LPSTR和LPWSTR 字符串
Visual C++使用LPSTR和LPWSTR字符串。
LPSTR類型字符串的定義是:指向一個空字節結尾的ANSI格式的字符串數組的指針。可是,由於咱們是以空字節的位置來判斷LPSTR字符串的終止的,因此,在LPSTR中是不容許字符串中還有第二個空字節存在。一樣,LPWSTR是一個指向空字節終止的Unicode格式的字符串的指針,它的中間也不容許有空字節存在。LPWSTR中的W指Wide,它是微軟對Unicode的另外一種說法。
可能咱們也會碰到LPCSTR和LPCWSTR類型的字符串。其中的C表示Constant(常量)。這種字符串是不能被API函數修改的。除此之外,LPCSTR都與LPSTR相同。同理,LPCWSTR除不能修改外,其它的都與LPWSTR相同。
再說LPTSTR,LPTSTR通常都用在條件編譯中,就象TCHAR同樣。如下是一個例子代碼:
#ifdef UNICODE
typedef LPWSTR LPTSTR; // 在Unicode下LPTSTR與LPWSTR是相同的
typedef LPCWSTR LPCTSTR; // 在Unicode下LPCTSTR與LPCWSTR是相同的
#else
typedef LPSTR LPTSTR; //在ANSI下LPTSTR與LPSTR是相同的
typedef LPCSTR LPCTSTR; //在ANSI下LPTCSTR與LPCSTR是相同的
#endif