このTIPSが3年前くらいにあったら、私自身助かったのですが・・・。
毎回ヘッダファイルを調べたりするので、まとめておきます。
Javaの場合
Javaはすっきりしていて、- java.lang.String
- java.lang.StringBuffer
- char[]
- byte[]
エンコードを気にしなくてよいのならば、上の2つで用は足ります(たぶん)。
Cの場合
純粋なC言語では、- char *
- unsigned char *
日本語(MBCS)を扱う場合に、unsignedにするか、キャストしないとよく泣かされます。
C++の場合
純粋なC++言語では、- char *, unsigned char *
- const char *, const unsigned char *
そもそも、純粋なC++なんてよく知りません。
VC++の場合
MS-C(DOS用コンパイラ)時代から使ってますが、Microsoftはいろんなことをしてくれます。ざっくりあげると、(unsignedは省略)
- char *, const char *
- wchar_t *, const wchar_t *
- OLECHAR *, const OLECHAR *
- _TCHAR, const _TCHAR *
- LPSTR, LPCSTR
- LPWSTR, LPCWSTR
- LPOLESTR, LPCOLESTR
- LPTSTR, LPCTSTR
- CString
- BSTR
- CComBSTR, _bstr_t
charとwchar_tとOLECHARと_TCHAR
まず文字型から。C言語標準は、char(1バイト)です。
その後、JavaのようにUnicodeを持つための文字型が、wchar_t(2バイト)です。 ↓
typedef unsigned short wchar_t;
なお、OLECHARもWin32環境ならばwchar_tと同じです。
Win32でない環境は、OLECHAR=char(らしい)。
さらに、プリプロセッサで両方を切り替えるための文字型が、_TCHARです。
_MBCSが定義してあれば、_TCHAR = char
_UNICODEが定義してあれば、_TCHAR = wchar_t
_UNICODEが定義してあれば、_TCHAR = wchar_t
LP~
LP~は、long pointer~の省略です。実際には、far pointerです。far *とは、64KBのセグメントの壁がどうのと言っていた時代の話で、知らなければそれはそれで幸せです。
さて、C = const, W = wchar_t, T = _TCHARと置き換えれば、機械的に意味が分かります。
また、BSTRはOLECHAR *です。
- LPSTR = char *
- LPCSTR = const char *
- LPWSTR = wchar_t *
- LPCWSTR = const wchar_t *
- LPOLESTR = OLECHAR * = BSTR = LPWSTR(Win32)
- LPCOLESTR = const OLECHAR * = LPCWSTR(Win32)
- LPTSTR = _TCHAR *
- LPCTSTR = const _TCHAR *
char *とCString
char *のやっかいなところが、メモリ管理です。もちろん、
char buf[64*1024];
とすれば、軽くスタックに64KBの文字列バッファは取れます。しかし、ちゃんとメモリ確保するとなると、
char * buf = (char *)malloc(64*1024);
をしたのち、不要になれば、 free(buf);
をする必要があります。そこで、CStringクラスを使うと、メモリ管理を気にせずに可変長文字列を扱えるので、
本来のアプリケーションのロジックに専念できます。
位置づけ的には、JavaのStringがCStringと同じ感じになります。
また、Javaではガーベッジコレクションがあるので、
byte[] buf = new byte[64*1024];
をした後に、 buf = null;
しなくても、これがローカル変数ならば気にする必要はありません。char *とBSTR
面倒なことにCOMを作ると、BSTRを使うことになります。BSTRとは、BASIC Stringのことで、BASIC言語の文字列型です(たぶん)。
BSTRは、Unicodeで表現したnull終端の文字列とポインタの前にバイトサイズを持っています。
ちょうどPascal文字列(先頭に文字列サイズを持っている)とC文字列(null終端)を足したようなものです。
BSTRの定義は、
typedef OLECHAR * BSTR;
となっています。つまり、BSTR = LPOLESTR = LPWSTR(Win32)と同じです。BSTRはchar *と同様にメモリ管理をしないといけないです。
BSTR bstrMsg = SysAllocString(OLESTR( Hello ));
SysFreeString(bstrMsg);
SysFreeString(bstrMsg);
char *:
↓ポインタ | | | | | |
H | e | l | l | o | (null) |
48 | 65 | 6C | 6C | 6F | 00 |
wchar_t *:
↓ポインタ | | | | | |
H | e | l | l | o | (null) |
48 00 | 65 00 | 6C 00 | 6C 00 | 6F 00 | 00 00 |
BSTR:
| ↓ポインタ | | | | | |
size=10 | H | e | l | l | o | (null) |
0A 00 00 00 | 48 00 | 65 00 | 6C 00 | 6C 00 | 6F 00 | 00 00 |
BSTRとCComBSTRと_bstr_t
BSTRだとメモリ管理が面倒なので、用意されたのがCComBSTRと_bstr_tです。CComBSTRはATLのクラスで、_bstr_tはコンパイラCOMサポートクラス(なんじゃそりゃ)です。
CStringがchar *のメモリを管理してくれるのと同様に、CComBSTR(_bstr_t)がBSTRのメモリ管理をしてくれます。
(おまけ)COMクラスのプロパティの実装
ATLによるCOMクラスのプロパティ設定/取得の方法です。前提としてクラス変数は、以下の変数を定義しています。
CComBSTR m_Name;
CString m_csName;
プロパティの設定
設定は、BSTR文字列をCComBSTRへ代入するだけ。STDMETHODIMP CXWFUser::put_Name(BSTR newVal){
m_Name = newVal;
return S_OK;
}
また、CStringも代入するだけ。 CStringのコンストラクタにBSTR引数は存在しないが、LPCWSTR引数があるので渡すことができる。
STDMETHODIMP CXWFUser::put_Name(BSTR newVal){
m_csName = newVal;
return S_OK;
}
プロパティの取得
取得は、CComBSTRで変数を持っている場合は、CopyToしないと落ちる(らしい)。STDMETHODIMP CXWFUser::get_Name(BSTR *pVal){
m_Name.CopyTo( pVal );
return S_OK;
}
危険なコード
STDMETHODIMP CXWFUser::get_Name(BSTR *pVal){
*pVal = m_Name;
return S_OK;
}
また、CStringで変数を持っている場合は、AllocSysString()を呼んでBSTRを確保する。
STDMETHODIMP CXWFUser::get_Name(BSTR *pVal ){
*pVal = m_csName.AllocSysString();
return S_OK;
}
0 件のコメント:
コメントを投稿