文章目錄
- C語言中的字串
- C++語言中的字串
- Win32編程中的字串
- COM中的字串
C/C++中的字串問題在網上的講解一向非常含糊,存在各個層次的庫混用、濫用的情況,尤其是寬字元與窄字元等問題很難找到有效資料,本篇隨筆分享一下我長期收集到的一些比較準確的資料以及據此得到的個人理解.
C語言中的字串
C語言中提供了兩種字元類型char和wchar_t,C語言使用字元數組來表示字串,同時支援兩種直接量寫法:"abcd"和 L"abcd" 來表示字串常量文字量,C語言允許用字串常量來初始化字串。標準C函數庫提供了printf和wprintf兩個版本的輸出函數。
#include <stdio.h>
int main(){
char str[] = "abcd";
wchar_t wstr[] = L"abcd數學";
printf("%s\n",str);
wprintf(L"%s\n",wstr);
return 0;
}
純C語言環境下,可以使用兩個函數wcstombs和mbstowcs 來進行寬窄字串的互相轉換,下面一段是C語言中wcstombs的例子
#include <stdio.h>
#include <stdlib.h>
int main(){
char str[] = "abcd";
wchar_t wstr[] = L"bcda";
wcstombs(str,wstr,sizeof(str));
printf("%s\n",str);
return 0;
}
這兩個函數都聲明在C標準庫標頭檔stdlib.h中。其它配套的字串操作都在標頭檔string.h和wchar.h
C++語言中的字串
C++中我們有了字串類string和wstring,這兩個類都在標頭檔string當中,並且iostream中也提供了各自對應版本的輸出資料流:
#include <string>
#include <iostream>
int main(){
std::string str = "abcd";
std::wstring wstr = L"abcd";
std::cout<<str<<std::endl;
std::wcout<<wstr<<std::endl;
return 0;
}
C++中轉換就很容易了,構造字串的時候把另一個的迭代器傳入就可以了:
#include <string>
#include <iostream>
int main(){
std::string str = "abcd";
std::wstring wstr(str.begin(),str.end());
std::wcout<<wstr<<std::endl;
return 0;
}
對於已經存在的字串,可以用assign來賦值。因為寬字元有些窄字元中沒有的字元,所以當你要指定一些轉換規則時,可以使用標頭檔algorithm中的transform函數。其它字串相關操作也在標頭檔string的類定義當中。
Win32編程中的字串
但是我們實際編程中,遇到字元集問題比較多的情況是Win32編程。Win32SDK為了避免編譯器造成的差異,用宏定義了自己的一套類型系統,其中字元類型就是CHAR和WCHAR,比較特別的是,Win32編程支援編譯時間的Unicode和非Unicode指定,所以Win32SDK又提供了TCHAR類型,它會根據是否是Unicode環境自動選擇CHAR或者WCHAR類型,沒有特別要求時,我們一般應該使用TCHAR。
CHAR和WCHAR的字面值分別是"abcd"和L"abcd",而TCHAR對應的字面值是_T"abcd",或者TEXT("abcd")。
Win32類型系統中還定義了字串類型,見下表:
PSTR |
PCSTR |
LPSTR |
LPCSTR |
PTSTR |
PCTSTR |
LPTSTR |
LPCTSTR |
PWSTR |
PCWSTR |
LPWSTR |
LPCWSTR |
其中我們把STR的首碼分成了不同的顏色,紅色首碼可能是P或者LP,P表示指標,LP表示長整型指標。大部分系統中P和LP是同一類型,所以這個首碼是不會造成區別的,可能64位C++或者一些舊的16位C++環境中會有區別。
藍色首碼可能是C或者沒有,這個很簡單,表示是否是常量指標。
綠色首碼可能是T、W或者沒有,這對應著CHAR、WCHAR以及TCHAR。
對於轉換問題,Windows提供了兩個API函數,這裡就不實際舉例了,具體請參看MSDN:
MultiByteToWideChar WideCharToMultiByte
其它與這些類型配套的Win32API函數請參看:MSDN中的參考
MFC中的CString類型提供了這些API的封裝,編程時使用可以省去不少麻煩。
COM中的字串
COM中提供了一個BSTR類型,它是OLECHAR的字串形式(OLECHAR可能是WCHAR或者CHAR,取決於系統的OLE字元集),很多人因為看了它的宏定義:
typedef /* [wire_marshal] */ OLECHAR *BSTR;
認為它只是簡單的OLECHAR *甚至WCHAR*,但是並非如此。BSTR所指向的記憶體位址前幾個位元組也是被分配的空間,用於儲存BSTR的長度等資訊。所以BSTR對應著一整套相關操作函數:
SysAllocString
SysAllocStringByteLen
SysAllocStringLen
SysFreeString
SysReAllocString
SysReAllocStringLen
SysStringByteLen
SysStringLen如果你在自己分配的WCHAR*上使用這些函數,一定會導致問題。同樣道理,如果你試圖用delete去釋放BSTR,也會造成錯誤。但是有相當一部分針對WCHAR的Win32API可以用在BSTR上。
好了,就這麼多了,希望您讀了這篇隨筆以後能對各種環境中的字串有個整體認識。