C初心者が知っておきたいヘッダーファイルとリンクの基礎知識目指せ! Cプログラマ(終)(4/4 ページ)

» 2014年04月11日 18時00分 公開
[長沼立巳, 小山博史SSS(G)/ガリレオ]
前のページへ 1|2|3|4       

ヘッダーファイルにまとめておくと便利なもの

 先ほどの「inline」の例で、関数「half」のまったく同じ宣言が「main.c」と「test.c」の2箇所にありました。

inline double half(double arg) {
    return arg / 2.0;
}

 このように複数のファイルで同じ内容を参照する場合、それをヘッダーファイルにまとめられます。ヘッダーファイルを用意して、各ソースファイルはそれを参照するように整理すれば、修正があっても1カ所で済ませることができ、開発がしやすくなります。

#ifndef HALF_H_
#define HALF_H_
inline double half(double arg) {
    return arg / 2.0;
}
#endif // HALF_H_
half.h
#include <stdio.h>
#include <stdlib.h>
#include "half.h"
void test(void);
int main(void) {
    printf("1 / 2 = %f\n", half(1.0));
    
    test();
    return EXIT_SUCCESS;
}
main.c
#include <stdio.h>
#include "half.h"
extern inline double half(double arg);
void test(void) {
    printf("3 / 2 = %f\n", half(3.0));
}
test.c

 ヘッダーファイルの最初と最後にあるマクロは、ヘッダーファイルの内容が重複定義されないようにするためのものです。詳しくは前回を参照してください。

 このようにしておくと、「half」関数に変更があった場合でも「half.h」を変更するだけで済みます。インライン関数の他にも、次のようなものをヘッダーファイルに書いておくと便利です。

  • 必要なヘッダーファイルのインクルード
  • 定数マクロ
  • 関数型マクロ
  • 関数プロトタイプ
  • 型定義(typedefやstruct、enumなど)

 よく行われるのは、モジュール(ソースファイル)の外部インターフェースをヘッダーファイルにまとめておき、その機能を利用したい別のモジュールがそのヘッダーファイルをインクルードできるようにしておくというものです。

 次の例を参考にしてみてください。

#include "module1.h"
// このオブジェクトは外部から参照できる。
int module_value = 1;
// この関数は外部から呼ばれる。
int module_func(const struct STR *p) {
    /* ... */
    return MODULE1_ERROR_SUCCESS;
}
module1.c
#ifndef MODULE1_H_
#define MODULE1_H_
// 外部からオブジェクト module_value を参照できるようにする。
extern int module_value;
// 構造体 STR を宣言できるようにする。
typedef struct STR_t {
    int x, y;
} STR;
// 関数 module_func が返すコードを定義する。
#define MODULE1_SUCCESS (0x0000)
#define MODULE1_ERROR_UNKNOWN (0x0001)
#define MODULE1_ERROR_INVALID (0x0002)
// 外部から関数 module_func を参照できるようにする。
int module_func(const struct STR *p);
#endif // MODULE1_H_
module1.h
#include <stdlib.h>
#include "module1.h"
int main(void) {
    // modulde1 の module_value の値を参照する。
    printf("module_value = %d\n", module_value);
    
    // modulde1 の module_func 関数を呼び出す。
    STR str = { .x = 200, .y = 100};
    int code = module_func(str);
    printf("result = %d\n", code);
    
    return EXIT_SUCCESS;
}
main.c

今回学んだことのまとめ

  • ソースファイルと、そこからインクルードされるヘッダーを全て合わせたものを「翻訳単位」と呼ぶ
  • 別の翻訳単位の識別子を参照できるようにする処理を「リンク」(あるいは「結合」)と呼ぶ
  • 異なる識別子は結合されない
  • ファイル有効範囲を持ち、宣言と同時に初期化されている宣言を「外部定義」と呼び、実体が用意される
  • ファイル有効範囲を持ち、宣言と同時に初期化が行われていない宣言を「仮定義」と呼ぶ
  • 仮定義は、対応する外部定義が見つかったときはそれと結合され、見つからないときは0で初期化された定義とみなされる
  • ファイル有効範囲を持つ識別子に「static」を付けると「内部結合」になり、staticが無い場合は「外部結合」になる
  • 内部結合とは翻訳単位の中で行われる結合で、外部結合は翻訳単位を越えて行われる結合
  • 関数もオブジェクトと同様のルールで結合される。「extern」は省略可能
  • 「インライン関数」はルールが異なる。C99とは異なる仕様のコンパイラーもあるので注意して使うこと

プログラミングライフを楽しく

 今回で連載は終了です。連載を通して「Cには確かに学ぶだけの価値がある」と思っていただけたでしょうか。学んだことを活用して、皆さんのプログラミングライフがより楽しくなればと思っています。

 最後に、記事を読んでいただいた皆さん、ありがとうございました。

前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。