• ベストアンサー

windowsの構造体にはなぜ自身のサイズを指定しないといけないのか?

windowsのプログラミングをしていると、cbSizeというその構造体自身を 意味するメンバ変数がよく出てきます。 質問は、これが一体なぜ必要なのか?についてです。 内部でその構造体を生のメモリにコピーすることがあり、その場所では その構造体の宣言がなぜか参照できないからか?などと思っていますが、今一 よく解っていません。 これについてご存知方がいらっしゃいましたらご教授お願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8560/19456)
回答No.4

API関数をバージョンアップ出来るようにする為です。 例えば、最初のバージョンで、ある構造体のサイズが50バイトにしたとします。 このAPI関数を呼ぶ場合、どのアプリもcbSizeに50を入れて呼びます。 ある時、API関数に機能が追加され、構造体の中身がソックリ入れ替わり、70バイトになったとします。 古いアプリは、API関数が古いままのつもりで、cbSizeに50を入れて呼びます。 新しいアプリは、API関数が新しくなったつもりで、cbSizeに70を入れて呼びます。 ここで、新しいAPI関数は「古いアプリもサポートする必要がある」ので、cbSizeが50で呼ばれたら古いバージョンと同じ動きをして、cbSizeが70で呼ばれたら追加機能がある新しいバージョンでの動きをします。 このようにすれば「API関数に機能追加をしつつ、古いアプリもサポートできる」ようになります。 なお、API関数が追加機能の無い古いバージョンのまま、追加機能を利用したアプリを走らせて、そのアプリが「API関数が新しいバージョンになっているつもりでAPI関数を呼ぶ」と、古いAPI関数は「cbSizeが不正ですよ~」と言うエラーコードを返します。 アプリは、このエラーコードを見て「このバージョンのWindowsでは実行できません」などのエラー表示を行う事になります。 なお、API関数のバージョンが変わると「構造体の後ろに新しいデータが追加され、前の方は古いバージョンと同じになっている事が多い」ですが、そうとも限りません。 場合によっては「特定の数値変数のサイズが2から4に変わった」とか「特定の数値変数のサイズが4から8に変わった」などで、途中からズレてたり、中身がまるっきり違うなんて事もあります。 まとめると「cbSizeは、呼び出し元のアプリが、どのバージョンのAPI関数を呼んだつもりになっているかを、API関数に知らせる為の物」です。 なお「元からバージョンは1つしかなく、機能追加の予定もなく、今も機能は1つしかない」としても「将来、変わるかもしれない」ので「cbSizeでバージョン判定」が行われているAPI関数が多数あります。

qatatatfds
質問者

お礼

まずは、返答遅れてしまい、申し訳ありませんでした。 丁寧な解説ありがとうございます。なるほど。 dllのインターフェイスに当たる関数のアドレスが変わらない事を 利用した上手いバージョンアップの方法ですね。面白い。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

noname#208124
noname#208124
回答No.3

UI周りでは対象OSによって構造体のメンバが増えるなんぞいつものことです

参考URL:
http://msdn.microsoft.com/en-us/library/bb773352.aspx,http://d.hatena.ne.jp/NyaRuRu/20080303/p1
全文を見る
すると、全ての回答が全文表示されます。
  • notnot
  • ベストアンサー率47% (4856/10272)
回答No.2

#1の方のお書きの通りだと思いますが、もう少し違う言い方をすると、 「APIの機能アップをしたいのだが、今の引数構造体だと、新機能の細かい指定をする項目のエリアがない」というような事が起こると困るので、そういう場合に、「構造体の後ろに新項目を継ぎ足して、サイズをその分増やす」という方式を採っているわけです。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

 こんばんは。  此れに関して確証が無いのですが、私が読んだ書籍の中には、「指定された構造体のサイズで、windowsやdllのバージョンを判断して挙動を変える」と言った事が書いてありました。  実際に良く出てくるwindowsビットマップ用の構造体でも、そんな感じの使われ方をされています(必ずこういった使い方であるかどうかは不明です)。  http://ja.wikipedia.org/wiki/Windows_bitmap DWORD biSize;//ファイルの先頭からsizeof(BITMAPFILEHEADER)分下がった位置でsizeof(DWORD)分読み込む switch(biSize) { case sizeof(BITMAPINFOHEADER): //windowsビットマップの多くは此れ break; case sizeof(BITMAPCOREHEADER): //os/2 break; case sizeof(BITMAPV4HEADER): //win95, nt4.0 break; case sizeof(BITMAPV5HEADER): //win98, win2000 break; }

qatatatfds
質問者

お礼

早速の回答ありがとうございます。 皆様もおっしゃっているようにサイズで挙動を変えるが正解のようですね。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 構造体

    構造体を受け取って、メンバの値を変数に代入する部分での質問です。 lParamには構造体のアドレスが入っています。 strcpy(buf, ((struct mpoint*)lParam)->r); これによって構造体のrメンバの文字列値をbufにコピーしたいのですが、文法が違うようなので正しく直したものを教えてください。

  • 構造体変数がないとメンバ操作できないのはなぜ?

    C言語の構造体に関して質問がありますが、structで型を作成して、構造体変数にてメンバの代入・参照をする。ということなんですが、なんでメンバ操作には構造体変数からでないといけないのでしょうか? 直接、型枠にてメンバ操作をすれば良いのに、なぜ構造体変数から操作しないといけないのでしょうか? 「クラス」や「オブジェクト」みたいに、一々ゼロから作成したり、コピペで作成しなくても済むように、このような形になっているのでしょうか? 回答の方よろしくお願いします。

  • 構造体で・・・・

    構造体は配列を使用せずメモリ領域を獲得する関数を使用すること、 *構造体内部のメンバ名には配列を用いて良い。  という、条件があるのですが場合はどのようにすればよろしいでしょうか? どなたか教えてください。 構造体は以下のようになってます。 /*構造体の定義*/ struct seiseki{   char name[20];   int eig;   int suu;   int kok;   char rank[3]; };

  • 構造体の使い方

    構造体が定義されている場所では、 struct runqueue{ task_t としかないのに、実際の関数の部分では task_t *p = current というように、変数として宣言されている部分があるのですが、これにはどういった意味があるのでしょうか?

  • 構造体の静的な初期化

    構造体の静的な初期化で、初期化が書かれていないメンバーは、 どうなるのでしょうか。。? たとえば・・・ // 構造体の宣言 strcut MY_STRUCT {    int data1 ;    int data2 ;    int data3 ;    int data4 ; } ; // 変数宣言&初期化 static strcut MY_STRUCT st = {    .data1 = 100,    .data3 = 300 } ; ネットで調べると、 初期化で指示されていないメンバーは0に初期化される、 という記述も一つだけ見つけたのですが・・・これはC言語(C99)の仕様でしょうか? それともコンパイラ依存の仕様でしょうか?

  • 構造体型のポインタ変数を含む構造体

    struct seiseki_tag { Int32 math ; Int32 english ; Int32 science; } ; typedef struct seiseki_tag SEISEKI ; struct personal_tag { Char name ; Int32 num ; SEISEKI *sptr } : typedef struct personal_tag PERSONAL ; struct info_tag { PERSONAL person_info ; } ; typedef struct info_tag INFO ; たとえば、上記のように3つの構造体があり、PERSONAL構造体のメンバーに SEISEKI構造体の型を持つポインタ変数が含まれているような場合で、下記のように INFO型のポインタ変数からSEISEKI構造体のメンバーを参照する方法を教えてください。 PERSONAL構造体メンバーのnameやnumは INFO *info ; info->person_info.name ; info->person_info.num ; のように参照すると思いますが、sptrが示すSEISEKI構造体のメンバーへの アクセスができません。下記のように参照を試みたのですがコンパイルは 通るのですが、実際に参照できていませんでした。 INFO *info ; SEISEKI *seiseki ; seiseki = info->person_info.sptr ; seiseki->math ; 判りにくい説明で申し訳ありませんが、どなたか教えていただければと思います。 よろしくお願いいたします。

  • 構造体について

    linuxのソースコードを呼んでいる者ですが、構造体について、実際に使う方法が分かりません。 ソースコードを少し書き換えて改良したいのですが、構造体が定義されているので、それをそのまま引用しないといけないので分からなくなってしまいました。 例えば、それぞれの関数のなかで最初の変数宣言の部分にstructが付いているものもあれば、付いていないものもあります。 この差はなんなのでしょうか?

  • 構造体のメンバのメモリ確保について

    構造体の中の一部のメンバだけをmalloc関数で メモリ確保したいのですがどのように宣言すればよいのでしょうか? vc++6.0を使用しています。 初歩的な質問ですみませんがお願いします。

  • 【VC++2005 MFC】構造体のコピーについて

    【VC++2005 MFC】構造体のコピーについて 構造体をコピーする時、単純に「=」で代入しているのですが、先輩に 「それじゃコピー出来ないから各メンバごとに代入するような関数作れ」 と言われました。 私自身、C言語の初心者ですが、ネットで調べてみると、単純に「=」で代入出来る ような気がしております。 ただ拝見したサイトに記載されている構造体は型が「int」「char」なのですが、 「CString」を使っていたり、構造体の中に更に構造体が入っていたりする場合も 単純に「=」で代入出来るのでしょうか? (というか、実際にコーディング、デバッグして、コピー出来ている事は確認しているん ですが、先輩いわく、「CStringとかのクラスが含まれている場合はダメだと思う。 メモリが壊れると思う」との事でした。)

  • プログラムの原理について

    プログラムはメモリ上どのように展開されているのか、宣言した変数はメモリにどう割り付けられるのか、変数を参照したり、変数に値を入れるときはどういう仕組みになっているのか等わかりやすく教えてください。お願いします。 また、宣言、定義などといった言葉に関しての質問になるのですが、定義は記憶が割り当てられていて、宣言は割り当てられていないと本にはあるのですが、これはメモリとスタックとの違いでよいのでしょうか?また、構造体は定義されていると書かれているのですが、その構造体の中のintの宣言は、定義になるのでしょうか?

PAR02 LEDが青くならない
このQ&Aのポイント
  • PAR02のLEDが充電完了後に青くならない問題が発生しています。
  • 電源をONにしてもLEDが青くならず、接続もできない状況です。
  • エレコム株式会社のPAR02に関する問題です。
回答を見る