ヘッダファイルの勉強

include< >とinclude" "の違い?

include<>を使用すると,プリプロセッサは「システム標準のディレクトリ」内でヘッダーファイルを検索する。
include""を使用すると,プリプロセッサは「カレントディレクトリ⇒コンパイラーの-Iオプションなどで命名されたディレクトリ⇒システム標準のディレクトリ」の順でヘッダーファイルを検索する。

実験

以下の3種類のファイルを作成する。

/* main.c */
#include<stdio.h>
#include<thank.h>

int main(){
	thank();
	return 0;
}

/* thank.h */
void thank(void);

/* thank.c */
#include<stdio.h>
#include<thank.h>

void thank(void){
	printf("Thank you!\n");
}

これでコンパイルすると,

$ gcc main.c thank.c
main.c:3:18: fatal error: thank.h: そのようなファイルやディレクトリはありません
compilation terminated.
thank.c:3:18: fatal error: thank.h: そのようなファイルやディレクトリはありません
compilation terminated.

システム標準のディレクトリにはthank.hがないのでエラーがでる.ということで,以下のように書き直す。

/* main.c */
#include<stdio.h>
#include"thank.h"

int main(){
	thank();
	return 0;
}

/* thank.h */
void thank(void);

/* thank.c */
#include<stdio.h>
#include"thank.h"

void thank(void){
	printf("Thank you!\n");
}

同様にコンパイルすると

$ gcc main.c thank.c
$ ./a.out 
Thank you!

さっきと違い無事に実行ファイルが作成できる。

#ifndefとか#endifって何?

#ifndef
機能 : 識別子が定義されていないかどうかの判定
書式 :

#ifndef <識別子名><処理>

詳細 : <識別子名>が未定義なら<処理>を実行。<処理>が複数行にわたる場合は、処理ブロックの最後を示すために#endifを記述する。

#endif
機能 : #ifdef、#ifndefなどによる処理ブロックの最後を明示
詳細 : #ifndefの結果が「真」なら続く<処理>を1行実行。複数行の処理を実行させたい場合は、その最後に#endifを記述してブロックの終端を示す。処理の構造を分かりやすくするため、1行の処理の最後に#endifを記述してもよい。

実験

以下の2種類のファイルを作成する。

/* main.c */
#include "num.h"
#include "num.h"

int main(){
	return 0;
}

/* num.h */
int number = 3;

これでコンパイルすると,

$ gcc main.c 
In file included from main.c:2:0:
num.h:1:5: error: redefinition of ‘number’
 int number = 3;
     ^
In file included from main.c:1:0:
num.h:1:5: note: previous definition of ‘number’ was here
 int number = 3;
     ^

変数numberが再定義されているというエラーが出る。したがって、num.hを以下のように書きなおす。

/* num.h */
#ifndef _NUM_H_INCLUDED_
#define _NUM_H_INCLUDED_
int number = 3;
#endif

同様にコンパイルすると

$ gcc main.c
$ 

といったように、コンパイル完了しエラーを回避できた。