たのしい工学

プログラミングを学んで、モノをつくりたいひと、効率的に仕事をしたい人のための硬派なブログになりました

【独学するコンピュータサイエンス】ファイルスコープと構造体の基本

   

ビットフラグでデータを管理

あり、なしのデータを管理するようなプログラムは2進数のビットフラグとして演算処理をおこなうことでデータを扱うことも可能になります

外部関数とextern宣言

局所変数では考えられない事ばかりです。そしてその危険性も少しは分かるのではないでしょうか。変数が関数内に閉じ込められていたおかげで関数としての独立性は高まり、その関数が一度完成してしまえば、その関数の引数の仕様が変わらない限り関数自体を変更する必要はありません。
ところが外部変数の場合その様な事は無関係です。もしどこかの関数で値を変更した場合、その影響がどの場所でどの様に起こるのかを丹念に調べ、修正しなければなりません。
関数が極少数ならまだ良いでしょう。外部変数も一つ二つならまだ良いでしょう。関数の数が数十を越えた辺りから、そして外部変数が別の外部変数に依存し出したら、想像してみてください。分かり易く例えましょう。関数を数百とし、そのうちの三割で外部変数の読み書きを行っているものとします。一つの外部変数の値を変更した場合プログラムにどの様な影響が出るかを調べる事は、砂漠の中から一粒の宝石を探し出すようなものであり、至難の極みです。
外部変数の導入は慎重に、そして出来る限り回避すべきです。

外部変数の static 指定

extern 定義とは異なり static 指定の外部変数は、定義を行った翻訳単位でのみ有効です。もしどうしても外部変数が必要になったら static 定義を行い、その翻訳単位内でのみその変数を使用するのが好ましいでしょう。そうすればその外部変数の識別子と値が他のファイルへ流れ出る恐れは無くなり、外部変数の危険性が少しは薄らぐからです。

複数ファイルで共通の外部変数を使用する場合

複数ファイルで共通の外部変数を用いるのは極力避けます。しかし必要になる場面もあるでしょう。その様な時はヘッダー・ファイルを用いるのが良いと思います。
ヘッダー・ファイルではその変数の仮定義、若しくは宣言を記述します。それを必要とするファイルでそのヘッダー・ファイルをインクルードします。
定義は二つの方法が考えられます。唯一つの .c ファイルで定義を記述する方法。もう一つは宣言とは別のヘッダー・ファイルで定義を行い、唯一つのファイルだけでインクルードします。

int 型の外部変数 global の宣言を行うヘッダー・ファイルを delc.h とし、 c ファイルでその変数を定義するなら次の様になります。


/* decl.h の中身。べき等は略 */
extern int global; /* 宣言だけ */

---------------------------------------------------

/* とある c ソース・ファイル*/
#include <decl.h>
extern int global = 20; /* 定義。extern はなくても良い */

構造体型の実体の作成

構造体型の宣言は構造体の型を宣言しただけです。通常の他の型名 char や int もそうである様に、実際に使用するには識別名を指定して記憶領域を割り当てなければなりません。ですから構造体型のオブジェクトの定義が必要です。
構造体型を struct tag { char c; }; と宣言します。これまで変数の定義は char c; 等と型名の後に識別名を記述しました。それは構造体型も同じですから struct tag st; 等となります。 st が実体の識別子でありそれは struct tag 型です。struct タグ名 で一つの型名なのをお忘れなく
型ですから記憶クラス指定子も型修飾子も使用可能です。それらを指定すればメンバー変数は全てそれらに従います。先の struct tag 型を用いて const struct tag cst; とすれば、メンバー変数である char型の c も const 修飾されます。 static const struct tag c2; とすれば、char 型の c も static const 指定したと見なされます。

構造体型の互換性

複数ファイルに構造体の宣言がそれぞれされている次の場合はどうでしょう。


/* ----- file1.c ----- */
struct tag_hand
{
int left;
int right;
};

/* ----- file2.c ----- */
struct tag_hand
{
int right;
int left;
};

タグ名は同じですがメンバー変数の順番が異なります。これも異なる型です。要するにタグ名が同一、構造体宣言リストが同一のものだけが同一の構造体型です。規格ではここまで厳密に定義していないもののこの様に考えた方が何かと良いです。
構造体に限らず、ファイル・スコープが必要な宣言や仮定義は一般にヘッダー・ファイル内で記述します。必要に応じてそのヘッダー・ファイルをインクルードすれば、構造体の宣言の記述を間違えて型の互換性が無くなってしまう様な事がありませんし手間も省け、一石二鳥です。

構造体型変数の初期化と const 修飾

構造体型変数、或いはそのメンバーが const 修飾されているのなら、構造体型変数の宣言と同時に初期化を記述する必要があります。これも従来の型の変数の初期化と考え方は同じです。

構造体型の宣言、実体作成、初期化

構造体型は一度宣言を行いコンパイラーに型を知らせます。その後その型が使用可能となるので実体が作成可能です。実体の作成と同時に初期化も記述可能です。
構造体型の宣言の規則を思い出してください。宣言は中括弧を閉じた直後に終了し、セミコロンで終了するのではないと説明しました。これを利用すると宣言と実体作成、初期化を一度に記述可能です。

構造体はクラスの概念に通じるものです。
構造体変数の定義 → クラスインスタンスの作成
構造体のメンバへのアクセス → クラスのプロパティへのアクセス

ポインタとあわせて構造体を理解すると、オブジェクト指向の考え方がぐっと理解しやすくなります。

ではでは!

 - コンピュータサイエンス