最小限の実行可能なマルチファイルスコープの例
ここでstatic
は、複数のファイルにわたって関数定義のスコープにどのように影響するかを示します。
交流
#include <stdio.h>
/* Undefined behavior: already defined in main.
* Binutils 2.24 gives an error and refuses to link.
* /programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/
/* OK: only declared, not defined. Will use the one in main. */
void f(void);
/* OK: only visible to this file. */
static void sf() { puts("a sf"); }
void a() {
f();
sf();
}
main.c
#include <stdio.h>
void a(void);
void f() { puts("main f"); }
static void sf() { puts("main sf"); }
void m() {
f();
sf();
}
int main() {
m();
a();
return 0;
}
GitHubアップストリーム。
コンパイルして実行:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main
出力:
main f
main sf
main f
a sf
解釈
sf
ファイルごとに1つ、2つの別々の関数があります。
- 単一の共有機能があります
f
いつものように、スコープが小さいほど良いので、static
可能であれば常に関数を宣言してください。
Cプログラミングでは、ファイルは「クラス」を表すためによく使用され、static
関数はクラスの「プライベート」メソッドを表します。
一般的なCパターンはthis
、最初の「メソッド」引数として構造体を渡すことです。これは、基本的にC ++が内部で行うことです。
それについて規格が言うこと
C99 N1256ドラフト 6.7.1「ストレージクラス指定子」static
は、「ストレージクラス指定子」であると述べています。
6.2.2 / 3「識別子のリンケージ」は次のstatic
ことを意味すると言いますinternal linkage
:
オブジェクトまたは関数のファイルスコープ識別子の宣言にストレージクラス指定子staticが含まれている場合、識別子には内部リンクがあります。
6.2.2 / 2はinternal linkage
、この例のように動作することを示しています。
プログラム全体を構成する翻訳単位とライブラリのセットでは、外部リンケージを使用した特定の識別子の各宣言は、同じオブジェクトまたは関数を示します。1つの変換単位内で、内部リンケージを持つ識別子の各宣言は、同じオブジェクトまたは関数を示します。
ここで、「翻訳単位」は前処理後のソースファイルです。
GCCがELF(Linux)用にどのように実装するのですか?
STB_LOCAL
結合。
コンパイルすると:
int f() { return 0; }
static int sf() { return 0; }
シンボルテーブルを次のように分解します。
readelf -s main.o
出力には以下が含まれます。
Num: Value Size Type Bind Vis Ndx Name
5: 000000000000000b 11 FUNC LOCAL DEFAULT 1 sf
9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
したがって、バインディングはそれらの間の唯一の重要な違いです。セクションValue
へのオフセットにすぎない.bss
ため、異なることが予想されます。
STB_LOCAL
ELF仕様のhttp://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.htmlに記載されています。
STB_LOCALローカルシンボルは、それらの定義を含むオブジェクトファイルの外には表示されません。同じ名前のローカルシンボルが互いに干渉することなく複数のファイルに存在する可能性があります
表現するのに最適な選択static
です。
staticのない関数はSTB_GLOBAL
で、仕様には次のように記載されています。
リンクエディターが複数の再配置可能なオブジェクトファイルを組み合わせる場合、同じ名前のSTB_GLOBALシンボルを複数定義することはできません。
これは、複数の非静的定義のリンクエラーと一貫しています。
を使用して最適化を開始する-O3
と、sf
シンボルはシンボルテーブルから完全に削除されます。外部からは使用できません。TODO最適化がない場合に、シンボルテーブルに静的関数を保持する理由 それらは何にでも使用できますか?
こちらもご覧ください
C ++の匿名の名前空間
C ++では、静的ではなく匿名の名前空間を使用することをお勧めします。これにより、同様の効果が得られますが、型定義がさらに非表示になります。名前のない名前空間と静的関数の比較