static(ファイル/モジュールレベル):
staticとして宣言された変数や関数は、そのコンパイルモジュール(ファイル)にスコープが制限されます。extern:
重要: staticは実装の隠蔽用、externはモジュール間のリンク用。
例:
main.c:
static int hidden_var = 5; extern int shared_var; int main() { printf("shared %d", shared_var); }
shared.c:
int shared_var = 10;
他のファイルからhidden_varを使用しようとすると、リンクエラーが発生します。
異なるモジュールで異なる修飾子static/externを持つ同じ名前の変数を定義した場合、何が起こりますか?
答え: 各static変数(例えば、異なるファイルのstatic int foo;)は完全に独立したオブジェクトです。extern int foo;の宣言は、名前がfooの共有グローバル変数を探します。staticとexternを混合することはできません—これは、あるファイルでfooがstaticとして定義され、別のファイルでexternとして宣言されると、リンクエラーを引き起こします。
物語 プロジェクトで、異なるモジュールに同じ名前の関数が重複していることが発見されました(staticなし)。リンカーはそのうちの1つしかリンクせず、もう1つは「失われ」、アプリケーションのロジックに影響を与えました。
物語 大規模プロジェクトで、
int counter;というグローバル変数が2つのモジュールに宣言されましたが、どちらもexternなしで行われました。その結果、アプリケーションの動作はリンクの順序に依存し、時折競合するシンボルが発生しました。
物語 モジュールはスコープが誤って定義された関数を使用していました:それはstaticとして定義されており、開発者は別のソースからそれを呼び出そうとしました—プログラムはexternに修飾子を変更するか(またはstaticを削除しない限り)構築されませんでした。