Cプログラムのコンパイルプロセスは、いくつかのステージから成ります:プリプロセッシング(preprocessing)、コンパイル(compilation)、アセンブリ(assembling)、リンク(linking)。歴史的にこのようなスキームは、ツール間の責任を分離し、ビルドプロセスの維持や設定を容易にすることを可能にしました。
問題:各ステージがどのように機能するかを理解していないと、「未定義の参照」やコードの重複、マクロの誤用による直感的でないバグ、複数ファイルにわたるコードのスケーリング時の問題に直面することがあります。
解決策:各ステージが特定の機能を実行することを理解する必要があります:プリプロセッサは# define、# includeなどのディレクティブを処理し、コンパイラは元のCコードをアセンブリに変換し、アセンブリは機械コードに、リンクはすべてのオブジェクトファイルとライブラリを最終的な実行可能ファイルに結合します。
コードの例:
元のコードの断片:
#include <stdio.h> #define PI 3.14 int main() { printf("%f ", PI); return 0; }
ステージを明示的に指定したgccの呼び出しの例:
gcc -E program.c # プリプロセッシング gcc -S program.c # コンパイル(アセンブリ前) gcc -c program.c # アセンブリ(オブジェクトファイル前) gcc program.o -o prog # リンク(linking)
主な特徴:
コンパイルの段階でのディレクティブ# include "file.h"は何をしますか?
#Includeはファイルの内容を呼び出しの場所に直接挿入します。コンパイルの開始前のプリプロセッシングの段階で。同じファイルを二重にインクルードすると、オブジェクトの重複定義やリンクでのエラーが発生する可能性があります。
関数の定義が1つのファイルにあれば、別のファイルで使用するのに十分ですか?
いいえ、ヘッダーファイルでの宣言(プロトタイプ)または少なくともextern宣言が必要です。そうしないと、「関数の暗黙の宣言」や「未定義の参照」などのエラーがリンク時に発生する可能性があります。
Staticとして宣言された変数を他のファイルから使用できますか?
いいえ。staticは変数または関数のスコープを現在のファイルに制限します。つまり、そのようなシンボルは他のオブジェクトファイル内のリンカには見えません。
初心者が2つのソースファイルに同じ名前の関数を実装します。リンクの段階で「関数の複数定義」という奇妙なエラーが発生します。
利点:
欠点:
宣言用の.hファイル、定義用の.cファイルを作成します。ヘッダーファイル保護のために#ifdefを使用します。すべてのファイルはリンカを介して最終プログラムに接続されます。
利点:
欠点: