おえぷろべい

お絵かきとかプログラミングとか米国株投資についてのなんやかんや

ファイルの分割について(C言語)

f:id:feci:20210810151051j:plain

C11

 

C11におけるファイルの分割について。

 

C言語では、1つのプログラムをざっくりと3つのファイルに分割して管理します。

 ①プロトタイプ宣言(.h)
 ②ユーザー定義関数の宣言(.c)
 ③main関数(.c)

 

 

それではさっそく例を見ていきましょう。

①プロトタイプ宣言(calc.h)

#ifndef _CALC_H_           //まだ_CALC_H_というものが定義されていなければ…
#define _CALC_H_           //ここでそれを定義する。もう定義されていれば#endifに飛ぶ。

//プロトタイプ宣言
double da(doubledouble); //_CALC_H_が定義されていればここの処理は飛ばす

#endif                     //define _CALC_H_のための記述

 

 

②ユーザー定義関数の宣言(calc.c)

#include "calc.h"               //プロトタイプ宣言のヘッダーファイル読み込み

//ユーザー定義関数の宣言
double da(double adouble b) {
  double c = (a + b/ 2.0;
  return c;
}

 

 

③main関数(main.c)

#include <stdio.h>                    //スタンダードioヘッダーファイルの読み込み
#include "calc.h"                     //calcヘッダーファイルの読み込み

//main関数
void main() {
  double d1d2d3d4[10];
  double a = 1.2b = 3.5c = 2.7;
  int i = 0;

 d1 = da(ab);
  d2 = da(4.15.7);
  d3 = da(c2.8);
  d4[0= d1;
  d4[1= d2;
  d4[2= d3;

 for (ii < 3i++) {
    printf("d%d = %f\n"id4[i]);
  }
}

C言語では1つのプログラムをこのような感じで3つのファイルに分けて管理します。

 

プロトタイプ宣言はヘッダーファイルに書きます。

ヘッダーファイルにある3つの#の記述は、二重インクルードというよく分からない現象を回避するための記述らしいです。

 

_CALC_H_の記述はべつにどんな文字列でも動作的には問題なくOKです。

ただ読みやすい構成の観点から言えば、ここの文字列は自身のファイル名と拡張子をアンダースコアで区切って書くのが昔からの通例らしいです。

 

 

ちなみにですが、VisualStudio2017以降のバージョンのコンパイラでは、このおまじないの記述は必要ないらしいです。

こっちで書かなくてもコンパイラくんが勝手にやってくれるみたいです。

 

しかし古いコンパイラくんだとそんなありがたい自動補完機能は存在しないので、とにかく不必要でもヘッダーファイルにはこの3つの記述を書く癖をつけておいたほうがいいのかもしれませんね。

 

また、#ifndefと#defineと#endifはマクロといい、C言語の文法そのものとは関係ない記述らしいです。

ちなみにマクロとは、コンピューターに指示を与えるのではなくコンパイラに指示を与えるためのものらしいです。

 

 

閑話休題

 

②と③のCファイルには①のヘッダーファイルを読み込むための #include "calc.h" を記述します。

このincludeの部分、なんでstdio.hはギュメ(山括弧)で囲うのにcalc.hはダブルクオーテーションで囲うのかについてですが、これは、stdio.hがC言語やVisualStudio側に用意されているヘッダーファイルなのに対して、calc.hは自作のヘッダーファイルだからです。

 

<>はすでに用意されている.hをincludeするときに使いますが、””は自作の.hをincludeするときに使います。

 

 

ファイル分割の他の例について。

①プロトタイプ宣言その1(calc.c)

#ifndef _CALC_H_           //まだ_CALC_H_というものが定義されていなければ…
#define _CALC_H_           //ここでそれを定義する。もう定義されていれば#endifに飛ぶ

//プロトタイプ宣言
void fa(intint);
void fb(intint);

#endif                     //define _CALC_H_のための記述

 

 

②プロトタイプ宣言その2(showResult.h)

//これわざわざ別ファイルに分ける必要あるの?
#ifndef _SHOW_RESULT_H_
#define _SHOW_RESULT_H_

//プロトタイプ宣言
void fc();

#endif

 

 

③ユーザー定義関数の宣言その1(calc.c)

#include "calc.h"       //プロトタイプ宣言のヘッダーファイル読み込み

//グローバル変数
int i = 0;

//ユーザー定義関数
void fa(int aint b) {
  i = a + b;          //iに演算結果を代入
}

void fb(int aint b) {
  i = a - b;          //iに演算結果を代入
}

 

 

④ユーザー定義関数の宣言その2(showResult.c)

#include "showResult.h" //プロトタイプ宣言のヘッダーファイル読み込み
#include <stdio.h>      //組み込み関数を使うので必要

extern int i;           //他のCファイルで定義されているグローバル変数iを読み込み

void fc() {
  printf("%d\n"i);  //iの値を表示
}

 

 

⑤main関数(main.c)

#include <stdio.h>       //組み込み関数を使うので必要
#include "calc.h"        //ユーザー定義関数(fa,fb)を使うので必要
#include "showResult.h"  //これを分ける意味がわからない

extern int i;            //他のCファイルで定義されているグローバル変数iを読み込み

//main関数
void main() {
  int ia = 2ib = 3;

 fa(iaib);
  printf("%d + %d = %d\n"iaibi);

 fb(iaib);
  printf("%d - %d = %d\n"iaibi);

 printf("%d - %d = "iaib);
  fc();
}

今回は5つのファイルに分割していますが、なぜshowResultなどというヘッダーファイルやCファイルが必要なのかは、まったくの謎です。

 

ふつうにプロトタイプ宣言はcalc.hにまとめて、ユーザー定義関数の宣言はcalc.cにまとめたらいいと思うんですけどね。

まあ謎です。

 

さて、グローバル変数をどの分割ファイルに記述するのかですが、これについては明確なルールはないようです。

Cファイルでさえあれば、どのファイルに定義してもいいみたいです。

 

んで、他のファイルにて定義しているグローバル関数をそのファイルで使うには、そのグローバル関数を参照する処理よりも上の行に extern データ型 変数名; と記述しないといけないようです。

例えば今回だとcalc.cで宣言しているグローバル変数iをmain.cで使いたいわけですから、main.cの上のほうの行に extern int i; と記述しないと、main.cでグローバル変数iを参照する処理をすることができないわけですね。

 

あとは各分割ファイルに適切にヘッダーファイルをincludeして終わりです。

stdio.hは、組み込み関数を使用するときには必ず読み込む必要があります。

 

その他の自作のヘッダーファイルについては、必要に応じてファイルごとにincludeしたりしなかったりといった感じですね。

 

 

以上です。