C言語を使っていると様々なファイルに出くわすことがある。ここでは以下の4種類のファイルの違いと役割について述べる。
名称 | 拡張子 |
---|---|
Cファイル または ソースファイル | .c |
実行ファイル | .out .exe |
オブジェクトファイル | .o |
ヘッダファイル | .h |
Cファイル/ソースファイル(.c)
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
C言語を使うときに最初に触れるであろうファイル。このファイルにコンピュータにさせたい命令を記述する。
これは人間が理解しやすく、命令を与えやすいような書き方をしているが、ただ単に与えられた命令をこなすコンピュータにとっては無駄な情報が多く不便であり、基本的にコンピュータはこのファイルを実行しない。
これらの特徴からこのファイル自体はだだのテキストファイルと同様に扱われることが多い。
基本的にという記述が気になる場合は「コンパイラ」と「インタプリタ」について調べるとよい。ここでは混乱の元となるため省略する。
Cファイルは設計図 ただの文字列で簡単に編集ができるが、それ自体は何もできない紙。
実行ファイル(.out/.exe)
[DEL]ELF[STX][SOH][SOH][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][ETX][NUL]
(以下省略)
実行ファイルを専用のエディタや環境を用意することなく閲覧・編集しないでください。
特に、cat
などのコマンドを使用しての閲覧・編集は絶対にしないでください。
実行ファイルを閲覧しようとすると、上に示したような意味不明な文字列が並びます。
これらは制御文字と呼ばれ、アルファベットなどと異なりその文字自体が特殊な扱い方をされます。これらの文字には決まった見た目というものが存在しないため、環境によって異なる見た目で表示されたり、見かけ上存在しないかのように扱われることもあります。
制御文字は直接コンピュータに何かしらの処理をさせることがあるため、単に閲覧しようとして制御文字を表示しただけで何らかの処理が内部で行われることもあります。 そのため専用の環境を使用せずに閲覧や編集をすることはプログラム外、使用しているコンピュータそのものに何らかの悪影響を与える可能性があるためやめましょう。
なお、この例では、実際の実行ファイルの制御文字をただの文字に手動で置き換えたものを記述しています。例えば[DEL]
はDELETE
と呼ばれる制御文字が使用されていたことを示します。
(2023/09/29修正) 制御文字ではなくELFヘッダというものらしいが、無知なため全く説明ができない。
プログラムを作った後にcc
やgcc
などのコマンドを使用することで生成されるファイル。再度このファイルをコマンドとして打ち込むことでプログラムが実行される。
実行ファイルはコンピュータが実行することだけを考えた純粋な命令やデータのみが記述されたファイルで、実際に実行することが可能である。
Cファイルが設計図なら、実行ファイルは設計図から組み立てられた機械のようなものといえる。
機械を分解して中身を覗いても設計図など出てこないため、Cファイルと異なり閲覧や編集はできない。
この機械を直接分解して組みなおす、ドライバーやドリルのなどの工具のような「バイナリエディタ」というツールが存在するが、これを用いて実行ファイルを修正することはまずない。
cc
やgcc
などのコマンドは、人間の為のプログラミング言語を機械が実行しやすい形に書き直す操作をしているといえる。
実行ファイルは機械 実際に何らかの行動を起こすが、直接仕組みを理解したり挙動を変えたりできない。
オブジェクトファイル(.o)
[DEL]ELF[STX][SOH][SOH][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][SOH][NUL]
(以下省略)
オブジェクトファイルを専用のエディタや環境を用意することなく閲覧・編集しないでください。
特に、cat
などのコマンドを使用しての閲覧・編集は絶対にしないでください。
C言語で大きな規模のプログラムを作成する際に使用するファイル。
大きくて複雑なプログラムをたった1つのCファイルで作成するのはあまり良いとはいえない。
そこで複数のCファイルを用意し、それらにプログラムを分けて書く手法が用いられる。これを分割コンパイルと呼ぶ。
しかし、複数のCファイルがあり、そこからいきなり1つの大きな実行ファイルを作成するというのは無駄が大きい。
それぞれのCファイルから小規模な実行ファイルを作成し、それを最後にまとめる方が良いだろう。
複数枚の設計図から1台の機械を作るのではなく、一度個々の部品を作ってから最後に組み立てるのである。
こうすることで何度も実行ファイルを作成する際に、Cファイルからコンピュータ用の命令に書き換えるのではなく、オブジェクトファイルを流用すればよいため、高速で処理が終わる。
オブジェクトファイルはコンピュータが実行するための命令やデータが記されているため閲覧・編集ができず、また一部のCファイルから作成したファイルの為、実行しようにも命令が足りず動かない。
そのためオブジェクトファイルは単体だと何もできないゴミとなってしまう。
オブジェクトファイルは機械部品 編集も実行もできないが、容易に使いまわせて機械を作れる。
ヘッダファイル(.h)
#ifndef TEMP_H
#define TEMP_H
void func(void);
#endif
おそらく4種類のファイルの中で最も理解が難しいファイル。
そもそもこのファイルは、プログラムを分けるために別々のファイルにプログラムを書いたが、異なるファイルで同じ機能を使いたいから、そこだけ1つのファイルにまとめて書きたいという無茶苦茶な要求を叶えるために作られたファイルである。
矛盾したことをやろうとしているのだから、複雑な仕組みになって当然ともいえる。
ヘッダファイルは#include
を使用することで使うことができるが、実はこの文、ただ単にヘッダファイルの中身をその場で展開しているに過ぎない。ヘッダファイルの中身をコピペするのが#include
の役目といえるだろう。なお、ヘッダファイルに限らず、Cファイルなどのファイルを#include
することも可能だが、これは一般に悪い使用方法とされる。
この、別々のファイルで同じ機能を使用したいという目的と、#include
されるとそのまま中身が展開されるという仕様を知っていれば、ある程度理解がしやすくなるだろう。
大前提として、意図して行う場合を除き、ヘッダファイルに変数や関数などのメモリを占領するようなものを記述してはいけない。
ヘッダファイルには様々なものを記述するが、最も使われるのは関数だろう。
関数の場合、定義を書いてしまうと#include
した全てのファイルで定義が展開されてしまうので、ヘッダファイルにはプロトタイプ宣言のみを記述する。
その他多くの使用方法については割愛する。ヘッダファイルの記述に関しては以下の記事でわかりやすく紹介されていたのでそちらを参照されるとよいだろう。
https://qiita.com/MoriokaReimen/items/7c83ebd0fbae44d8532d
ヘッダファイルは別のCファイルの機能を共有するための定義・宣言をするもの 別のファイルに有用なものがあることを教えてくれるが、このファイルに書いた内容は#include
したすべてのファイルで展開されるため注意する。