C言語の構造体定義の種類と使い分け

概要
1. typedefを使用しない&タグ名あり
2. typedefを使用しない&タグ名なし
3. typedefを使用する&タグ名あり
4. typedefを使用する&タグ名なし

1. typedefを使用しない&タグ名あり方法

typedefを使用しない場合、構造体はタグ名を使用して定義・宣言を行います。

struct hoge_tag {
  char a;
  short b;
  long c;
};

int main(void)
{
  struct hoge_tag hogeA;
  struct hoge_tag hogeB;

  hogeA.a = 1;
  hogeA.b = 2;

  hogeB.a = 100;
  hogeB.b = 200;
  ・・・
}

この場合、宣言時にstructキーワードを省略することは出来ません
また、タグ名を使用して何度でも別々のメモリ領域に構造体を宣言することが可能です。構造体宣言に必ずstructキーワードが必要になる為、あまり用いられることがないです。
構造体の中に構造体が入れ子になっている事を明示する目的で使用することがあります。

struct hoge_child_tag {
  char a;
  short b;
};

struct hoge_tag {
  struct hoge_child_tag hc;
  char c;
  long d;
};

int main(void)
{
  struct hoge_tag hogeA;

  hogeA.hc.a = 100;
  ・・・
}

しかしこれも必須の定義方法ではないです。
別途、typedefを使用した方法で簡素に定義することは可能です。
これについて後記します。

2. typedefを使用しない&タグ名なし

タグ名を使用しない場合、構造体定義の最後に変数名を定義しなければなりません。

struct {
  char a;
  short b;
  long c;
} hogeA;

int main(void)
{
  hogeA.a = 1;
  hogeA.b = 2;
  ・・・
}

変数名(hogeA)は、実体としてメモリ上に定義・宣言が同時に行われ、その直後から使用することが出来るようになります
最も簡素に使用できる反面、構造体を複製することが出来ませんので、ほとんど用いられることはないと思います。

3. typedefを使用する&タグ名あり

typedefはある型名を別の型名で再定義させたい場合に使用します。

typedef short int16;

int main(void)
{
  short a;
  int16 b;        /* short b;と同じ */
}

この例では、shortという既存の型名をint16というものに再定義させています。
main関数内でa,bという二つの変数を宣言していますが、どちらも同じshort型で
宣言した状態となります。
この再定義の仕組みを構造体へ適用すると、次のようになります。

typedef struct hoge_tag {
  char a;
  short b;
} HOGE_TAG;

int main(void)
{
  struct hoge_tag hogeA;
  HOGE_TAG hogeB;

  hogeA.a = 1;
  hogeB.a = 100;
  ・・・
}

この例では、hoge_tagというタグ名をHOGE_TAGという型名で再定義しています。
最初の例のshortに相当するのが

struct hoge_tag {
  char a;
  short b;
}

の部分で、int16に相当するのが、HOGE_TAGという事になります。
2のhogeAはメモリ上の実体を表しました。
しかしここでのHOGE_TAGは、同じ定義方法のように見えますが、全く違います。
これはtypedefによって再定義された型名を表しますので、実体ではありません

その為、この構造体を使用する為には、必ず宣言が必要になります。

struct hoge_tag hogeA;
HOGE_TAG hogeB;

宣言方法はタグ名を使用する方法と、typedef宣言名を使用する方法との2通りありますが、typedef宣言名を使用するやり方の方が簡素に書けるので、好まれます。
また、上のどちらでも宣言可能という事は、タグ名を省略して

HOGE_TAG hogeB;

の方法のみで宣言させる事も可能という事です。

4. typedefを使用する&タグ名なし

3からタグ名を省略した形です。

typedef struct {
  char a;
  short b;
} HOGE_TAG;

int main(void)
{
  HOGE_TAG hogeA;
  HOGE_TAG hogeB;

  hogeA.a = 1;
  hogeB.a = 100;
  ・・・
}

HOGE_TAGという型名によって何度でも構造体宣言が出来ます。
一番使いやすい方法だと思います。

以上が、構造体の4つの定義・宣言の方法になります。
このうち、1、2だけが定義と宣言が合体した特殊な方法になりますので、
注意して下さい。

以上になります。

参考:
typedef を使う方法
構造体