構造体は型を作るものだといいました。しかし、型を作らずにオブジェクトだけを作ることもできます。正しくは、型を作ったが、あとから使えないと言えばいいでしょうか? どうも、2つとも正確ではないような気がしますが、まぁ、今回はそんな感じの構造体についてのお話です。
それでは今回の要点です。
では、いってみましょう。
構造体は、実は次のようにすれば「構造体型の宣言」と「オブジェクトの宣言」を同時に行うことができます。
struct SStudent { char szName[16]; int nJapanese; int nMath; int nEnglish; } student;
{ } の部分をのけて考えてみれば
struct SStudent student;
となり、できるのもうなずける話です。
では、この時 SStudent をのけてしまうとどうなるでしょうか?
struct { char szName[16]; int nJapanese; int nMath; int nEnglish; } student;
オブジェクトはあるわけであり、student.szName も問題なく使えそうです。ただ、型名がなくなってしまうのでオブジェクト全体を関数に渡すことはできなさそうです。唯一の不安は、「文法的に許されているか」です。
これは、文法的に許されています。名前のない構造体なので、これを無名構造体と呼びます。
しかし、無名構造体が作れるのはいいですが、こんなもの使うんでしょうかね? 型名がないので、型名の必要なあらゆることができなくなってしまいます。それでは構造体にする意味はあるのでしょうか? 普通の変数を作ったのでいいと思います。
なので、普通この無名構造体はある決まった時にしか使わないと思います。それは、構造体を共用体内にネストするときです。
例えば、次の共用体を見て下さい。
union UDWord { unsigned long l; // x.l 1ダブルワード(1ダブルワード=4バイト) struct { unsigned short l; // x.s.l 下位ワード unsigned short h; // x.s.h 上位ワード } s; // 2ワード(1ワード=2バイト) };
前回の共用体は4バイトを1バイト単位で扱うものでしたが、今回の共用体は4バイトを2バイト単位で扱うというものです。
前回の共用体で分かったように、配列を使うと結果がエンディアンネスによって変わってしまいます(改めて第1部第55章参照)。ということで、きちんとした名前を付けて扱うことにしました。こうすれば、エンディアンネスが変わったときもこの共用体の宣言の名前を交換するだけですむからです。
しかし、共用体の各メンバは全部先頭アドレスが同じになってしまいます。上位2バイト、下位2バイトと名前を変えるにはどうすればいいでしょうか? って、上でもうやってますね。構造体を使えばいいのです。こうすれば、unsigned long l と構造体の先頭アドレスが同じになります。構造体のメンバ l と h のアドレスはこれで異なるようになります。(実はこの構造体のサイズが4になるとは限らないのですが、ここではなるものと考えておいて下さい。)
ここで、こんな構造体に果たして型名が必要か考えてみて下さい。え? 必要ですって? そう思う人は型を作っても構いませんけどね...。まぁ、必ずしも必要でないとは思います。こういうときに無名構造体を使えばいいということです。
また、無名共用体も可能です。例えば次のようなものです。
union UDWord { unsigned long l; // x.l struct { union { unsigned short s; // s.l.s / s.h.s struct { unsigned short l; // s.l.b.l / s.h.b.l unsigned short h; // s.l.b.h / s.h.b.h } b; } l, h; } s; };
ちょっと分かりにくいですが、確かに無名共用体ですね。
さらに、無名列挙型もできます。
enum { ENUM1, ENUM2, ENUM3 };
変数がなくても列挙子自体は使えるので、これだけでも利用できます。しかし、名前を付けておくと後々便利なこともあるので、名前はつけておいた方がいいかもしれません。
では、今回の要点です。
次回はもっと精密に操作してみたいと思います。そう1バイト単位よりも小さい単位でです。では、次回まで。
Last update was done on 2000.8.6
この講座の著作権はロベールが保有しています