#pragma twice

KAB-studio > プログラミング > #pragma twice > 156 Version 8.14 構造体を読み解く

#pragma twice 156 Version 8.14 構造体を読み解く

前のページへ 表紙・目次へ 次のページへ

 Version 8.14
構造体を読み解く

さて、今回は前回使った

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
#if (_WIN32_IE >= 0x0400)
    union
    {
        TVITEMEX itemex;
        TVITEM item;
    } DUMMYUNIONNAME;
#else
    TVITEM item;
#endif
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

を読み解きます
かなり複雑……
それは、いろんなものが複雑に絡み合ってるから。しかも、それぞれが独
立してるものだから
順に憶えていけば大丈夫?
大丈夫。じゃ、まずは外側、構造体全体の話から

typedef struct tagTVINSERTSTRUCT {
// 略
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

これでくくってあるってことは、この頭のと最後のとが関係してるってこ
と?
そういうこと。えっと、 typedef は教えたよね
 Version 5.08 ( No.073 ) でね
ここでは

typedef struct tagTVINSERTSTRUCT {
// 略
} TVINSERTSTRUCT;



typedef struct tagTVINSERTSTRUCT {
// 略
} FAR *LPTVINSERTSTRUCT;

が組み合わさってるって考えて
 , でふたつ一緒に型を作れるのね
で、まずは上の

typedef struct tagTVINSERTSTRUCT {
// 略
} TVINSERTSTRUCT;

から。これは

struct tagTVINSERTSTRUCT {
// 略
};

って構造体の別名として TVINSERTSTRUCT の付けてる……
付けてる?
みたいな感じ
何それ
前回の CTreeCtrl::InsertItem() で試してみると分かるけど、 
tagTVINSERTSTRUCT そのものは型になってません
へ? 型として使えないの?
そう、だからただの名前、何にも使えない名前
いみなー
だから実際には

typedef struct tagTVINSERTSTRUCT {
// 略
} TVINSERTSTRUCT;

は、この構造体を TVINSERTSTRUCT って名前で使う、って意味だと考えて
ください
……質問!
はい火美ちゃん
前に、構造体はクラスと同じだって教えてもらったよね
 Version 7.07 ( No.127 ) でね
ってことは

struct TVINSERTSTRUCT {
// 略
};

でいいんじゃないの?
今はね
あ、昔は違ったって話?
そゆこと。クラスがない、 C 言語の時代にはこの書き方では構造体は作
れなかったんです
だから typedef 使ってた?
そゆこと。そういう書き方しか前はできなくて、それが今も API には
残ってるってこと
じゃあ、昔の typedef 使ったのは今の書き方に読み替えちゃっていい
の?
うん、それで大丈夫だと思うよ。じゃ、その次の

typedef struct tagTVINSERTSTRUCT {
// 略
} FAR *LPTVINSERTSTRUCT;

んーと、 FAR * ってのが増えたんだね
 FAR は Version 6.03 ( No.103 ) の far が #define されたもので、こ
こで書いてあるとおり空白になります
ってことは * だけ、ってことはポインタ?
そう。 typedef は最後の単語だけが新しい型の名前って指定されるか
ら、ここでは〈構造体のポインタ〉として LPTVINSERTSTRUCT って型が作ら
れてることになります
これって

typedef TVINSERTSTRUCT *LPTVINSERTSTRUCT;

でもいいんだよね
もちろん。一緒に型を定義するのは昔の C 流ってとこかな。逆に言え
ば、ここでも
さっきみたいにこう読み替えちゃえばいいのね
そゆこと。さて、次に構造体の中身

    HTREEITEM hParent;
    HTREEITEM hInsertAfter;

はただのメンバ変数だよね。次の

#if (_WIN32_IE >= 0x0400)

はプリプロセッサだね #if は Version 6.06 ( No.106 ) でやったけど、 
_WIN32_IE はなに?
これは組み込みマクロのひとつ
 Version 6.07 ( No.107 ) でやったね。 WIN32 ってどういう意味?
 WIN32 は32ビットウィンドウズっ意味だけど、まぁ〈最近のウィンド
ウズ〉って読み替えていいかな。 Version 2.14 ( No.025 ) 参照
今日は参照多いね…… IE って、インターネットエクスプローラー?
そう。つまりこの組み込みマクロは、 IE のバージョンを示してるんで

 IE のバージョンなんて関係あるの?
あるんです。実はツリービューコントロールってウィンドウズ95が出た
頃よりもバージョンアップしてて、そのバージョンアップって IE と一緒に
されてるから
ってことは IE4 が入ってるか入ってないかでツリービューコントロール
のできることが違う?
そう、だからバージョンを調べて構造体の中身を変えてるんです
これだと、 IE のバージョンが低いと

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
    TVITEM item;
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

で、高いと

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
    union
    {
        TVITEMEX itemex;
        TVITEM item;
    } DUMMYUNIONNAME;
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

なわけね
そゆこと。ここまで分かれば、あとは
 union だけ! これは初めて見るのだね
そうだね。これって C 言語の時代からあるんだけど、分かりにくいのと
ちょっと危険なのだからあまり使われてないかな
憶えても使わない方がいい?
だね。でも使い方だけは教えておくから。まず

    union
    {
        TVITEMEX itemex;
        TVITEM item;
    } DUMMYUNIONNAME;

の DUMMYUNIONNAME は無視して
ダミーって付いてるものね。さっきの typedef struct 
tagTVINSERTSTRUCT の名前だけってのと同じ?
そんなとこ。で、 union の中身について。 union は〈あるメモリ領域を
いろんな変数に見せかける〉ことができます
???
つまり

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
    TVITEM item;
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

でもあるし

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;
    HTREEITEM hInsertAfter;
    TVITEMEX itemex;
} TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT;

でもあるってこと
どっちの変数にもなる?
そう。次の例が一番分かりやすいかな

    TVINSERTSTRUCT stInsertItem;
    TRACE( "%X\n", &( stInsertItem.item ) );
    TRACE( "%X\n", &( stInsertItem.itemex ) );
    // 64F4B8
    // 64F4B8

お、普通に item と itemex と両方使ってて……アドレスが同じ!
そう、ふたつメンバ変数があるように見えるけど、実際には同じメモリ上
に置かれてて、〈どういう型として扱うか〉だけが異なるってこと
……それってまずくない? たとえば、ここで TVITEM item の代わりに
int i とかやっても
できちゃいます
……それってヤバくない?
やばいよ。だからあまり使われてないし、こういう使い方も勧めないか

まさに教わるだけってことね

/*
    Preview Next Story!
*/
教わるだけのって……やっぱいつか使いたくなるかな
絶対なるよ
お、経験者は語る?
 C++ って、型がコンパイル時にチェックされるでしょ
 HWND に int 入れられないものね
そのあたりの柔軟性が欲しい時に……
 union に手を出しちゃうわけね
というわけで次回
< Version 8.15 通知メッセージの受け方 >
につづく!
 union は MFC もメッセージ処理に使ってたりするし
なら大丈夫なんじゃない?
どうかなぁ……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。