【C言語】構造体を定義する色々な方法


基本的な定義方法

struct Number {
   int value;
};

変数宣言時にはstructキーワードが必須です。

struct Number obj;
printf("%d", obj.value);

structキーワードを省略する方法は後半の「# 一般的な定義方法」で紹介します。

無名構造体

ラベル名を省略した構造体をその場で定義/利用することが可能です。

int main() {
   struct { int a; int b } pair;
   pair.a = 1;
   pair.b = 2;
}

ちょっとしたアルゴリズムを実現する際に重宝します。

一般的な定義方法

typedefキーワードと組み合わせる方法が一般的です。

typedef struct {
   int value;
} Number;

こうすることで、変数宣言時にstructキーワードが不要になります。

Number num;
printf("%d", num.value);

もちろん、ラベル名を明示することも可能です。

typedef struct Number_ { int value; } Number;

解説

typedefによる構造体宣言方法は見慣れない記法かもしれませんが、仕組み自体は単純です。そもそもtypedef自体は型の別名を付ける機能なのですが、これがtypedef 型 別名という宣言方法になっています。

そして今回紹介した構造体の特殊な記法はこのの部分に構造体を直接指定することで実現されています。

人によってはこのように書いたほうが最初は覚えやすいかもしれません。 やっていることは同じです。

struct Number_ { int value; };
typedef struct Number_ Number;

自己参照構造体

構造体のラベル名は基本的に省略するのが一般的ですが、自身の型をメンバに持つ構造体を作る際にはラベル名が必要になります。

typedef struct Node_ {
   struct Node_ *next;
   // Node *next; // この書き方は出来ない
                  // typedefによる別名Nodeの宣言がまだ確定していないため   
} Node;

メンバ宣言時の記述struct _Nodeが煩わしいと感じる場合は、前方宣言を行うと良いです。こうするとNodeと書くことが出来るようになります。

typedef struct Node_ Node;

typedef struct Node_ {
   Node *next;
} Node;

typedefによる構造体名とラベル名は同じでも良い

今回の例ではtypedefによる構造体名と構造体ラベル名を区別するために、アンダースコア付きのNumber_という名称で両者の区別をしていましたが、実際は同じ名前を付けても問題ありません(変数宣言時にはstructキーワードで両者を区別出来るため)。

struct Number a; // 構造体タグ名で宣言
Number b; // typedefによる別名で宣言

ただ、実際の開発では名前を区別したり、無名ラベルを用いる方が良いと思います。名前の重複や余計な型名が増えると、IDE側の機能が若干使いづらくなったりします。

XcodeのJump To Definition (^⌘J)機能やEclipseのOpen Declaration (F3)機能などがその良い例。構造体タグ名とtypedefの別名が同名だとジャンプ先の候補リストが表示されてしまう場合がある。名前重複が起こらなければ、定義箇所へのジャンプが一発で行えるようになる

ちなみに

ちなみにC++ではstruct Number {};と書くだけでstruct NumberNumber型の両者を定義してくれます。気の利くヤツです。


C++「どや」
私「うむ、これはいいものだ」

広告