開発効率化2:分割コンパイル

大規模なプログラムを作成する際, 1個の巨大なソースファイルのまま編集すると, 余計な手間・時間が費やされがちとなる. 複数の小さなファイルに分割し, 作業を楽にしよう.

教科書の該当範囲:第4.5節
参考書の該当範囲:なし

ソースファイルの分割

未完成です... とりあえず こちら (昨年度の授業内容)を参考に学習してください.


練習問題

pendraw.c を複数のソースファイル・ヘッダファイルに分割せよ.

まず安全のための準備として, 前回作成(したハズ)の2個のソースファイル pdcl.c(マクロ導入済み)と pendraw.c(構造体導入済み)とを ディレクトリ pendraw/ 内にコピーしておこう. そして,この問題の作業については, すべてこのディレクトリの中で実施しよう:

$  mkdir  pendraw/
$  cp  ../c-1113/pdcl.c  ./pendraw/
$  cp  ../c-1113/pendraw.c  ./pendraw/
$  cd  pendraw/

目標とする分割ソースファイルの構成:

$ ls
img.c
img.h
main.c
pdcl.c		# 今回,このファイルの内容は変更しません
pen.c
pen.h

$ cat  img.h
#ifndef IMG_H
#define ...
typedef struct { ... } Img;
extern void FillImg(...);
extern void ShowImg(...);
#endif ...

$ cat  img.c
#include ...
void FillImg(...) { ... }
void ShowImg(...) { ... }

$ cat  pen.h
#ifndef PEN_H
#define ...
typedef struct { ... } Pen;
extern void ShowPen(...);
extern void Draw(...);
extern void Ctrl(...);
#endif ...

$ cat  pen.c
#include ...
void ShowPen(...) { ... }
void Draw(...) { ... }
void Ctrl(...) { ... }

$ cat  main.c
#include ...
int Info(...) { ... }
int Game(...) { ... }
int Title(...) { ... }
int main(...) { ... }

pendraw の一括コンパイル:

$ cc  img.c  pen.c  main.c  -lncurses  -o  pendraw  -Wall

pendraw の分割コンパイル:

$ cc  -c  img.c  -Wall
$ cc  -c  pen.c  -Wall
$ cc  -c  main.c  -Wall
$ cc  img.o  pen.o  main.o  -lncurses  -o  pendraw

pdcl の一括コンパイル:

$ cc  pdcl.c  -o  pdcl  -Wall

上級者向け情報

pendraw の構造体変数 img について...

img.c

...
// 画像のメモリ領域を開放する関数
void FreeImg(Img *img)
{
	if (img == NULL) return;
	if (img->pixel != NULL) free(img->pixel);
	free(img);
}

// 画像のメモリ領域を確保する関数
Img *NewImg(int w, int h)
{
	Img	*img;
	img = (Img *)malloc(sizeof(Img));	// 軌跡画像構造体のメモリを確保
	if (img == NULL) return (NULL);
	img->w = w;
	img->h = h;
	img->pixel = (char *)malloc(sizeof(char)*w*h);	// 軌跡画像配列のメモリを確保  
	if (img->pixel == NULL) {
		free(img);
		return (NULL);
	}
	return (img);
}
...
これらの関数の追加に伴い,img.h の内容も変更.

main.c

...
int Game(...)
{
	...
	Img	*img;
		/* 画像構造体の操作をすべて関数化したし,
		構造体引数は参照渡しとすべきなので,
		画像構造体をすべてポインタとして使うことにする.
		これに伴い,&img の部分をすべて img に変更必要. */
	...
	img = NewImg(w, h);
	if (img == NULL) goto ERROR;
	FillImg(img, ' ');
	...
	FreeImg(img);
}

(c) 2018, yanagawa@kushiro-ct.ac.jp