C言語GUI入門|C言語プログラムが動くまで

C言語で書いたソースファイルは、そのままではWindows上で実行できません。GCCによってコンピューターが理解できる形式へ変換され、必要なライブラリと結び付けられることで、exe形式の実行ファイルになります。

この記事では、次の内容を解説します。

  • ソースファイルとは
  • コンパイルとは
  • リンクとは
  • 実行ファイルとは
  • exeファイルが作られる流れ

全体の流れは次のようになります。

ソースファイル
      ↓
前処理
      ↓
コンパイル
      ↓
アセンブル
      ↓
オブジェクトファイル
      ↓
リンク
      ↓
exe形式の実行ファイル

ここでは、まだプログラムの作成やコンパイルは行いません。まずは、ソースファイルがどのような仕組みでexeファイルになるのか、全体像をつかんでいきましょう。

C言語のプログラムは変換してから実行する

C言語は、人が読み書きしやすい形式でプログラムを記述するためのプログラミング言語です。

C言語で記述した内容を読めば、関数を呼び出していることや、計算していること、条件によって処理を分けていることなどを理解できます。

しかし、コンピューターのCPUは、C言語で書かれた内容をそのまま実行するわけではありません。CPUが直接実行するのは、機械語と呼ばれる命令です。

そのため、C言語のプログラムを動かすには、次のような変換が必要です。

人が理解しやすいC言語
          ↓
コンピューターが実行できる機械語

この変換を担当する代表的な開発ツールがGCCです。

GCCはソースファイルを読み取り、文法や型を確認しながら、最終的にWindowsで実行できるexeファイルを作ります。

種類主に利用するもの
C言語のソースコードプログラマー
機械語CPU
GCCソースコードを機械語へ変換する
Windows完成した実行ファイルを読み込んで起動する

図1:C言語から実行ファイルへの変換

この図から分かること

プログラマーが作成するのは、C言語で記述されたソースファイルです。しかし、CPUはソースファイルを直接実行できません。

GCCがソースファイルを変換することで、Windows上で実行できるexeファイルが作られます。ソースファイルと実行ファイルは、内容も役割も異なるファイルです。

ソースファイルとは

ソースファイルとは、プログラマーが作成したソースコードを保存するテキストファイルです。

C言語のソースファイルには、一般的に.cという拡張子を付けます。

ファイル名.c

たとえば、hello.cという名前で保存した場合、helloがファイル名、.cが拡張子です。

部分内容
helloファイル名
.cC言語のソースファイルを表す拡張子
hello.c完全なファイル名

ソースファイルには、C言語を使って次のような内容を記述します。

  • プログラムの開始位置
  • 変数や定数
  • 計算処理
  • 条件分岐
  • 繰り返し処理
  • 関数の定義や呼び出し
  • 画面への表示
  • キーボードからの入力
  • プログラマー向けのコメント

ソースファイルは通常のテキストファイルなので、Visual Studio Codeなどのテキストエディターで作成、表示、編集できます。

ソースファイルは設計図に近いもの

ソースファイルは、建物を作るときの設計図にたとえられます。

設計図には、どのような部屋を作るか、どこに柱を置くかなどが記載されています。しかし、設計図そのものを建物として利用することはできません。

C言語のソースファイルも同じです。どのような処理を行うかが記述されていますが、そのままではコンピューター上で実行できません。

建物の設計図
      ↓
設計図をもとに建築
      ↓
完成した建物

C言語では、次のように対応します。

ソースファイル
      ↓
GCCによる変換
      ↓
完成した実行ファイル

このように考えると、ソースファイルと実行ファイルの違いを理解しやすくなります。

ソースファイルと実行ファイルの違い

項目ソースファイル実行ファイル
主な拡張子.c.exe
主な内容C言語のソースコードCPUが実行する機械語など
主に作成するものプログラマーGCCやリンカー
編集方法Visual Studio Codeなどで編集する通常は直接編集しない
人が読む比較的読みやすいそのままでは読みにくい
Windowsでの実行そのままでは実行できない実行できる
変更方法ソースコードを書き換えるソースを書き換えて作り直す

ソースファイルを変更しても、すでに作成されている実行ファイルの内容は自動的には変わりません。

変更した内容を実行ファイルへ反映するには、ソースファイルからexeファイルをもう一度作り直す必要があります。

コンパイルとは

コンパイルとは、C言語で書かれたソースコードを、コンピューターが処理できる形式へ変換する作業です。

コンパイルを担当するプログラムをコンパイラーと呼びます。本コンテンツでは、コンパイラーとしてGCCを使用します。

コンパイラーは、単純に文字を機械語へ置き換えているだけではありません。ソースコードを詳しく解析しながら、次のような点も確認します。

  • C言語の文法が正しいか
  • 変数が正しく宣言されているか
  • 関数の呼び出し方が正しいか
  • データ型の使い方に問題がないか
  • 閉じ波かっこやセミコロンが不足していないか
  • 指定されたC言語規格に合っているか
  • 警告の対象になる記述がないか

問題が見つかった場合は、エラーや警告が表示されます。

コンパイルエラーとは

C言語の文法などに問題があり、コンパイラーが処理を続けられない場合に発生するのがコンパイルエラーです。

主な原因には、次のようなものがあります。

  • セミコロンを付け忘れている
  • 波かっこの対応が間違っている
  • 変数名を間違えている
  • 宣言していない関数や変数を使用している
  • データ型の使い方が正しくない
  • C言語として解釈できない文字がある

コンパイルエラーが発生した場合、exeファイルは完成しません。

ソースファイル
      ↓
コンパイルエラー
      ↓
変換を中止
      ↓
exeファイルは作られない

エラーを修正した後、あらためてコンパイルする必要があります。

エラーと警告の違い

コンパイラーが表示するメッセージには、主にエラーと警告があります。

種類意味exeファイル
エラー処理を続けられない問題通常は作られない
警告間違いの可能性がある問題作られる場合がある
メッセージなし問題が検出されなかった作られる

警告が表示されてもexeファイルが作られることがあります。しかし、警告は無視してよいという意味ではありません。

現在は動いているように見えても、入力内容や実行環境によって問題が起きる可能性があります。警告も内容を確認し、できるだけ解消することが大切です。

コンパイルという言葉には2つの使い方がある

コンパイルという言葉は、説明する場面によって少し違う意味で使われます。

使い方意味
狭い意味C言語のソースコードをアセンブリ言語へ変換する処理
広い意味ソースファイルから実行ファイルを作る処理全体

初心者向けの説明では、前処理、コンパイル、アセンブル、リンクをまとめてコンパイルと呼ぶことがよくあります。

一方、処理の内部を詳しく見る場合は、コンパイルとリンクを別の段階として扱います。

この記事では、個々の処理を説明するときは、コンパイルとリンクを分けて考えます。

前処理とは

C言語のソースファイルは、本格的にコンパイルされる前に前処理が行われます。

前処理を担当する仕組みをプリプロセッサと呼びます。

前処理では、主に次の作業が行われます。

  • ヘッダファイルに書かれた宣言を利用できるようにする
  • マクロを展開する
  • 条件付きコンパイルの対象を選ぶ
  • コメントを取り除く
  • コンパイラーが処理しやすい形へ整える

前処理が終わった内容は、コンパイラーへ渡されます。

ソースファイル
      ↓
プリプロセッサ
      ↓
前処理済みのソース
      ↓
コンパイラー

通常はGCCが前処理も自動的に行うため、プログラマーが毎回個別に操作する必要はありません。

アセンブルとは

狭い意味でのコンパイルによって、C言語のソースコードはアセンブリ言語へ変換されます。

アセンブリ言語は、C言語よりもCPUの命令に近い形式です。しかし、まだCPUが直接実行する最終的な機械語ではありません。

そこで、アセンブラーがアセンブリ言語を機械語へ変換します。この処理をアセンブルと呼びます。

C言語
   ↓ コンパイル
アセンブリ言語
   ↓ アセンブル
機械語

アセンブルによって、オブジェクトファイルと呼ばれるファイルが作られます。

オブジェクトファイルとは

オブジェクトファイルは、ソースファイルを機械語へ変換した中間ファイルです。

MSYS2のGCCでは、一般的に.oという拡張子が使われます。

ファイル名.o

オブジェクトファイルには機械語が含まれていますが、通常はそのまま実行できません。実行ファイルを構成する部品のひとつだからです。

たとえば、プログラムが複数のソースファイルに分かれている場合、それぞれから別のオブジェクトファイルが作られます。

ソースファイルA.c → オブジェクトファイルA.o
ソースファイルB.c → オブジェクトファイルB.o
ソースファイルC.c → オブジェクトファイルC.o

最後に、これらのオブジェクトファイルを結び付け、ひとつの実行ファイルを作ります。

図2:コンパイルとリンクの違い

この図から分かること

コンパイルは、ソースファイルを機械語の部品であるオブジェクトファイルへ変換する処理です。

リンクは、作成されたオブジェクトファイルと必要なライブラリを結び付け、ひとつの実行ファイルを完成させる処理です。

コンパイルとリンクは、どちらもexeファイルを作るために必要ですが、担当する役割が異なります。

リンクとは

リンクとは、オブジェクトファイルと必要なライブラリを結び付け、実行ファイルを作る処理です。

リンクを担当するプログラムをリンカーと呼びます。

リンクでは、主に次のものが結び付けられます。

  • 自分のプログラムから作られたオブジェクトファイル
  • ほかのソースファイルから作られたオブジェクトファイル
  • Cの標準ライブラリ
  • プログラムの開始や終了に必要な処理
  • 外部ライブラリ
  • Windowsの機能を利用するための情報

部品がひとつだけの小さなプログラムでも、Cの標準ライブラリやプログラム開始時の処理などが必要になります。

ライブラリとは

ライブラリとは、よく使われる機能をまとめたプログラムの部品です。

C言語には、文字の表示、文字列の処理、数学計算、メモリ管理などに利用できる標準ライブラリがあります。

ライブラリを利用すると、すべての処理を最初から自分で作る必要がありません。

自分で作成した処理
        +
ライブラリが提供する処理
        ↓
完成した実行ファイル

第4章以降で使用するGTK 4も、GUIアプリケーションを作成するためのライブラリです。

GTK 4のプログラムでは、自分のオブジェクトファイルとGTK 4のライブラリをリンクして、GUIアプリケーションのexeファイルを作ります。

ヘッダファイルとライブラリの違い

ヘッダファイルとライブラリは、同じものではありません。

種類主な役割
ヘッダファイル関数やデータ型の宣言をコンパイラーへ伝える
ライブラリ関数の実際の処理を提供する
オブジェクトファイル自分のソースコードを機械語へ変換した部品
リンカーオブジェクトファイルとライブラリを結び付ける

コンパイラーはヘッダファイルの宣言を使って、関数の呼び出し方が正しいか確認します。

リンカーは、ライブラリの中から必要な関数の実体を探し、オブジェクトファイルと結び付けます。

リンクエラーとは

コンパイルに成功しても、リンクに失敗する場合があります。これがリンクエラーです。

リンクエラーの主な原因には、次のようなものがあります。

  • 呼び出している関数の実体が見つからない
  • 必要なオブジェクトファイルが指定されていない
  • 必要なライブラリが見つからない
  • ライブラリの指定が不足している
  • 関数名が定義と呼び出しで一致していない
  • 異なる環境向けのライブラリが混在している

コンパイルエラーとリンクエラーの違いは、次のように考えられます。

コンパイルエラー
C言語の内容を機械語の部品へ変換できない

リンクエラー
機械語の部品は作れたが、必要な部品を結合できない

リンクエラーが発生した場合も、完成したexeファイルは作られません。

コンパイルとリンクを料理にたとえる

コンパイルとリンクは、料理の手順にたとえると理解しやすくなります。

コンパイルは、材料ごとに下ごしらえをする作業です。

野菜を切る
肉に下味を付ける
調味料を用意する

リンクは、準備した材料を組み合わせてひとつの料理を完成させる作業です。

下ごしらえした材料
     +
調味料
     ↓
完成した料理

C言語では次のように対応します。

料理C言語
材料ソースファイル
下ごしらえコンパイル
下ごしらえ済みの材料オブジェクトファイル
調味料や共通材料ライブラリ
材料を組み合わせるリンク
完成した料理実行ファイル

オブジェクトファイルは重要な部品ですが、それだけでは完成品ではありません。必要な部品とライブラリをリンクして、初めて実行ファイルになります。

実行ファイルとは

実行ファイルとは、OSがプログラムとして読み込み、CPUに処理させることができるファイルです。

Windowsでは、一般的に.exeという拡張子が使われます。

ファイル名.exe

exeはexecutableを短くした表記です。executableには、実行できるという意味があります。

実行ファイルには、主に次の内容が含まれます。

  • CPUが実行する機械語
  • プログラムで使用するデータ
  • プログラムの開始位置
  • 必要なDLLの情報
  • Windowsがファイルを読み込むための管理情報
  • メモリ上へ配置するときに必要な情報

ソースファイルとは異なり、実行ファイルの内容は人が直接読み書きするためのものではありません。

exeファイルはWindows向けの実行ファイル

exeファイルは、Windowsで使用される代表的な実行ファイルです。

ファイル名の例は次のようになります。

hello.exe
calculator.exe
tic_tac_toe.exe

ファイル名を見れば、それぞれ別のプログラムであることが分かります。

ただし、exeファイルであれば、どのコンピューターでも必ず動作するわけではありません。

実行するためには、次のような条件が関係します。

  • 対応するWindowsの種類
  • CPUの種類
  • 32ビットと64ビットの違い
  • 必要なDLLが存在するか
  • 使用しているライブラリが利用できるか
  • ファイルを実行する権限があるか

GTK 4を使用するGUIアプリケーションでは、exeファイルのほかにGTK 4が使用するDLLなども必要になります。配布に必要なファイルについては、第7章で詳しく扱います。

exeファイルは直接編集しない

プログラムの表示内容や処理を変更したい場合、通常はexeファイルを直接編集しません。

元のソースファイルを編集し、もう一度コンパイルとリンクを行います。

ソースファイルを編集
        ↓
コンパイル
        ↓
リンク
        ↓
新しいexeファイル

このため、プログラムを開発するときは、exeファイルだけでなくソースファイルも大切に管理する必要があります。

exeファイルが作られる流れ

ソースファイルからexeファイルが作られるまでを、もう一度詳しく整理します。

1. ソースファイルを読み込む
          ↓
2. 前処理を行う
          ↓
3. C言語をアセンブリ言語へ変換する
          ↓
4. アセンブリ言語を機械語へ変換する
          ↓
5. オブジェクトファイルを作る
          ↓
6. ライブラリやほかの部品とリンクする
          ↓
7. exe形式の実行ファイルを作る

各段階の役割は次のとおりです。

段階処理作られるもの
1ソースファイルを読み込むC言語の内容を取得
2前処理を行う前処理済みのソース
3コンパイルするアセンブリ言語
4アセンブルする機械語
5機械語をファイルに保存するオブジェクトファイル
6部品とライブラリを結合する実行に必要な内容を統合
7Windows向けにまとめるexeファイル

通常は、GCCがこれらの処理を順番に進めます。そのため、利用者からはひとつのまとまった処理に見えます。

処理の途中で作られるファイル

処理の内部では、複数の形式が使われます。

拡張子ファイルの種類主な内容
.cソースファイルプログラマーが記述したC言語
.i前処理済みファイル前処理が終わったソース
.sアセンブリファイルアセンブリ言語
.oオブジェクトファイル機械語に変換された部品
.exe実行ファイルWindowsで実行できる完成ファイル

通常のコンパイルでは、.i、.s、.oなどの中間ファイルを意識しなくても、最終的なexeファイルを作れます。

しかし、この流れを知っておくと、コンパイルとリンクが別の処理であることや、エラーが発生する段階の違いを理解しやすくなります。

図3:exeファイルが完成する7段階

この図から分かること

exeファイルは、ソースファイルから一度に姿を変えるわけではありません。前処理、コンパイル、アセンブル、リンクという複数の段階を通って作られます。

途中で文法エラーが見つかったり、必要なライブラリが見つからなかったりすると、処理は完了せず、exeファイルも作られません。

どの段階で問題が起きたかを確認することが、エラーを解決するための重要な手がかりになります。

exeファイルが実行されるときの流れ

完成したexeファイルを起動すると、Windowsがファイルの内容を確認してメモリへ読み込みます。

おおまかな流れは次のとおりです。

exeファイルを起動する
        ↓
Windowsがファイルを読み込む
        ↓
必要なDLLを確認する
        ↓
プログラム用のメモリを準備する
        ↓
プログラムの処理を開始する
        ↓
CPUが機械語を順番に実行する
        ↓
プログラムを終了する

ソースファイルが実行されているのではなく、ソースファイルから作られたexeファイルが実行されています。

DLLと実行ファイルの関係

DLLは、Dynamic Link Libraryを短くした名前です。複数のプログラムから利用できる機能をまとめたファイルです。

実行ファイルが必要とする機能の一部は、exeファイルの外にあるDLLから提供される場合があります。

実行ファイル
     +
必要なDLL
     ↓
プログラムを実行

必要なDLLが見つからない場合、exeファイルが存在していてもプログラムを起動できません。

通常の小さなコンソールプログラムでは意識する場面が少ないかもしれませんが、GTK 4を使用するGUIアプリケーションでは、多くのGTK関連DLLが必要になります。

コンソールプログラムとGTK 4プログラムの流れ

通常のコンソールプログラムとGTK 4を使うGUIプログラムは、基本的に同じ流れでexeファイルになります。

ソースファイル
      ↓
コンパイル
      ↓
リンク
      ↓
exeファイル

異なるのは、リンクするときに必要になるライブラリです。

種類主にリンクするもの
通常のコンソールプログラムCの標準ライブラリなど
GTK 4プログラムCの標準ライブラリ、GTK 4と関連ライブラリ

GTK 4プログラムでは、ウィンドウ、ボタン、入力欄などの機能をGTK 4のライブラリから利用します。

そのため、GTK 4のヘッダファイルとライブラリをGCCが見つけられるようにする必要があります。この情報を取得するために、第4章ではpkg-configを使用します。

各用語の関係

用語意味
ソースファイルC言語のソースコードを保存したファイル
コンパイラーソースコードを解析して変換するプログラム
コンパイルC言語を機械語に近い形式へ変換する処理
アセンブラーアセンブリ言語を機械語へ変換するプログラム
アセンブルアセンブリ言語を機械語へ変換する処理
オブジェクトファイル機械語に変換された未完成の部品
ライブラリ再利用できる機能をまとめた部品
リンカーオブジェクトファイルとライブラリを結合するプログラム
リンク必要な部品を結び付ける処理
実行ファイルOSがプログラムとして実行できるファイル
exeファイルWindowsで使われる代表的な実行ファイル

次の記事へ進む前に確認すること

次の内容を確認できたら、C言語プログラムが動くまでの全体像を理解できています。

  • ソースファイルはC言語のソースコードを保存したテキストファイル
  • C言語のソースファイルには.cという拡張子を付ける
  • CPUはC言語のソースファイルを直接実行しない
  • GCCがソースコードをコンピューター向けの形式へ変換する
  • コンパイルではソースコードの文法や型も確認される
  • アセンブルによって機械語のオブジェクトファイルが作られる
  • オブジェクトファイルは実行ファイルを構成する部品
  • リンクではオブジェクトファイルとライブラリが結び付けられる
  • Windowsの実行ファイルには.exeという拡張子が使われる
  • ソースファイルを変更した場合はexeファイルを作り直す必要がある
  • GTK 4プログラムでもコンパイルとリンクという基本的な流れは同じ

次の記事から、chap03ディレクトリを使って実際のファイルを準備し、C言語プログラムの作成へ進みます。