Loose-Info.com
Last Update 2022/11/27
TOP - 各種テスト - gcc - ファイル名の拡張子によるコンパイラの動作 - h

ファイル名の拡張子が「.h」であるときのコンパイラの動作・挙動

テスト概要

その1
・拡張子が「.h」であるファイルのコンパイル結果
・生成されたプリコンパイル済みヘッダファイルが存在する場合のコンパイル例

その2
プリコンパイル済みヘッダが存在する場合の、プリプロセッサの記述順序によるヘッダファイル選択に関する挙動の違い
(その1で作成したプリコンパイル済みヘッダファイルを使用した参考テスト)

その3
プリプロセッサの記述順序による、プリコンパイル済みヘッダファイルのみ存在する場合の検索挙動
(その1で作成したプリコンパイル済みヘッダファイルを使用した参考テスト)

実行環境

GCC-8.2.0
GNU C Library 2.28
GNU Binutils 2.31.1


コード例・出力内容中の表記

・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。

使用ファイル

各例共通

sample.h
/* 動作確認用ヘッダファイル */ #ifndef SAMPLE_H #define SAMPLE_H #define TEST_FLG 1 /* 使用ファイルを判別するためのマクロ */ struct Samp { int nsamp1; int nsamp2; }; int sampFunc(struct Samp s); #endif /* SAMPLE_H */

sample.c
/* ヘッダファイル内で定義されたマクロ利用の関数を定義した動作確認用ソースファイル sample.c */ #include "sample.h" int sampFunc(struct Samp s) { return s.nsamp1 + s.nsamp2 + TEST_FLG; }

main.c
/* ヘッダファイル内で定義されたマクロとsample.cで定義された関数を使用したソースファイル main.c */ #include "sample.h" #include <stdio.h> int main(void) { struct Samp smp; smp.nsamp1 = 1; smp.nsamp2 = 2; int n = sampFunc(smp); printf("n = %d\n", n); printf("TEST_FLG = %d\n", TEST_FLG); return 0; }

その1

・拡張子が「.h」であるファイルのコンパイル結果
・生成されたプリコンパイル済みヘッダファイルが存在する場合のコンパイル例

プリコンパイル済みのヘッダーファイルを作成するためにコンパイル実行
gccの引数に「.h」のファイルを指定した場合は、プリコンパイル済のヘッダファイルを生成
$ ls -l total 12 -rw-r--r-- 1 ****** ******** 293 *** ** **:** main.c -rw-r--r-- 1 ****** ******** 176 *** ** **:** sample.c -rw-r--r-- 1 ****** ******** 225 *** ** **:** sample.h $ gcc sample.h コンパイルを実行 $ ls -l total 1748 -rw-r--r-- 1 ****** ******** 293 *** ** **:** main.c -rw-r--r-- 1 ****** ******** 176 *** ** **:** sample.c -rw-r--r-- 1 ****** ******** 225 *** ** **:** sample.h -rw-r--r-- 1 ****** ******** 1774000 *** ** **:** sample.h.gch <--- プリコンパイル済みヘッダ $

プリコンパイル済みヘッダとの判別のため、sample.hの内容の書き換え
#define TEST_FLG 2 <--- 「1」を「2」に書き換え

ソースファイルのコンパイルを実行
sample.hを使用している場合は、
n = 1 + 2 + 2 = 5
TEST_FLG = 2
sample.h.gchを使用している場合は、
n = 1 + 2 + 1 = 4
TEST_FLG = 1
$ gcc main.c sample.c $ ls -l total 1768 -rwxr-xr-x 1 ****** ******** 18392 *** ** **:** a.out <--- 生成された実行ファイル -rw-r--r-- 1 ****** ******** 293 *** ** **:** main.c -rw-r--r-- 1 ****** ******** 176 *** ** **:** sample.c -rw-r--r-- 1 ****** ******** 225 *** ** **:** sample.h -rw-r--r-- 1 ****** ******** 1774000 *** ** **:** sample.h.gch $ ./a.out <--- 生成されたa.outを実行 n = 4 <--- sample.cは「sample.h.gch」を利用してコンパイルされている事を示す値 TEST_FLG = 1 <--- main.cも「sample.h.gch」が使用されている $

その2

プリコンパイル済みヘッダが存在する場合の、プリプロセッサの記述順序によるヘッダファイル選択に関する挙動の違い

上記の「その1」実行後の状態で、「main.c」の内容を書き換え(下記コードは書き換え後)
#include <stdio.h> <--- 上下逆に書き換え #include "sample.h" <---

ソースファイルのコンパイルを実行
sample.hを使用している場合は、
n = 1 + 2 + 2 = 5
TEST_FLG = 2
sample.h.gchを使用している場合は、
n = 1 + 2 + 1 = 4
TEST_FLG = 1
$ gcc main.c sample.c $ ls -l total 1768 -rwxr-xr-x 1 ****** ******** 18392 *** ** **:** a.out <--- 生成された実行ファイル -rw-r--r-- 1 ****** ******** 293 *** ** **:** main.c -rw-r--r-- 1 ****** ******** 176 *** ** **:** sample.c -rw-r--r-- 1 ****** ******** 225 *** ** **:** sample.h -rw-r--r-- 1 ****** ******** 1774000 *** ** **:** sample.h.gch $ ./a.out <--- 生成されたa.outを実行 n = 4 <--- 「sample.c」は「sample.h.gch」を利用してコンパイル TEST_FLG = 2 <--- 「main.c」は「sample.h」を利用してコンパイル $

その3

プリプロセッサの記述順序による、プリコンパイル済みヘッダファイルのみ存在する場合の検索挙動

上記の「その2」実行後の状態で、「sample.h」を削除し、コンパイルを実行
$ rm -frv sample.h <--- sample.hを削除 removed 'sample.h' $ ls -l total 1764 -rwxr-xr-x 1 ****** ******** 18392 *** ** **:** a.out -rw-r--r-- 1 ****** ******** 293 *** ** **:** main.c -rw-r--r-- 1 ****** ******** 176 *** ** **:** sample.c -rw-r--r-- 1 ****** ******** 1774000 *** ** **:** sample.h.gch <--- プリコンパイル済みヘッダのみ存在 $ gcc main.c sample.c main.c:4:10: fatal error: sample.h: No such file or directory #include "sample.h" <--- 「sample.h」が見つけられないことによるエラー ^~~~~~~~~~ compilation terminated. $

「main.c」の内容を再度書き換え(下記コードは書き換え後)
#include "sample.h" <--- 再度上下逆に書き換え #include <stdio.h> <---

ソースファイルのコンパイルを実行
$ gcc sample.c main.c $ ./a.out n = 4 <--- 「sample.c」は「sample.h.gch」を利用してコンパイル TEST_FLG = 1 <--- 「main.c」も「sample.h.gch」を利用してコンパイル $