27

私の本から:

.bss:

初期化されていないグローバル C 変数

一般:

まだ割り当てられていない初期化されていないデータ オブジェクト

明確な違いはないと言わざるを得ません。初期化されていない、割り当てられていないデータオブジェクトが何であるかさえよくわかりません...何もないようです。GNU のreadelfツールを使用して簡単な C コードを調べてみましたが、COMMON シンボルが 1 つも見つかりません。FORTRAN の COMMON 型は COMMON シンボルの例のようなものを読んだことがありますが、FORTRAN はわかりません

誰かが私のために2つを区別できますか? 可能であれば、うまくいけばCの例で?大変感謝しています。

編集この投稿から、ここの変数 c :

int c;
int main() {} ...

コモンである必要があります。しかし、使用objdump -tすると、cが.bssにあることがわかります...

混乱している

4

4 に答える 4

25
// file a.c
// file-scope

int a = 0;  // goes into BSS

a.cオブジェクトファイルにコンパイルした後a.oaシンボルはBSSセクションに入ります。

// file b.c
// file-scope

int b;  // goes into COMMON section

b.cオブジェクト ファイルにコンパイルした後b.obシンボルは COMMON セクションに入ります。

とをリンクするa.oと、 とb.oの両方ab記号が BSS セクションに入ります。共通シンボルは、実行可能ファイルではなく、オブジェクト ファイルにのみ存在します。Unix における COMMON シンボルの考え方は、特定の条件下で単一の共通シンボルの下で (異なるコンパイル単位で) 同じ変数の複数の外部定義を許可することです。

于 2013-05-30T12:26:24.730 に答える
15

コモンは、リンク段階の前にのみ表示されます。Commons は後で bss または data に入るものですが、それがどこに行くかはリンカ次第です。これにより、異なるコンパイル単位で定義された同じ変数を持つことができます。私の知る限り、これはほとんどの場合int foo;extern int foo;.

仕組みは次のとおりです。

$ cat > a.c
int foo;
$ cat > b.c
int foo;
$ cat > main.c
extern int foo;
int main(int argc, char **argv) { return foo; }
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ objdump -t a.o | grep foo
0000000000000004       O *COM*  0000000000000004 foo
$ objdump -t b.o | grep foo
0000000000000004       O *COM*  0000000000000004 foo
$ objdump -t x | grep foo
0000000000600828 g     O .bss   0000000000000004              foo
$

これが機能するのは、さまざまなコンパイル ユニット内の変数のうち、多くても 1 つが初期化されている場合のみであることに注意してください。

$ echo "int foo = 0;" > a.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ echo "int foo = 0;" > b.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
b.o:(.bss+0x0): multiple definition of `foo'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$

これは恐ろしいものであり、古代のシステムとの互換性であり、決してそれに頼るべきではありません. 物事を適切に行います-すべてのコンパイル単位でグローバル変数の定義を1つだけにし、ヘッダーを介して他の場所でexternを宣言します。

于 2013-05-30T12:24:47.857 に答える
9

リンク中に許可するcommonと、異なるユニットが同じ変数を宣言でき、リンカーはそれらを同じ場所に配置します。型は同じである必要さえないので、ある種のリンク時の結合です。これはCOMMONFortran の機能です。C のリンクを許可しないcommonと、リンク時エラーが発生します。このようなcommonリンクは、初期化されていないグローバルに対してのみ可能です。

行き先のグローバルbssは、C が 0 に初期化されると定義する初期化されていないグローバルです。ほとんどのオブジェクト形式は、サイズのみが指定され、ローダーがセクション全体をゼロで埋めるセクションをサポートします。

PS: 使用する場合は、シンボルをセクションに強制gccするオプションを使用できます。これは、Art が主張するように、適切で推奨される方法です。-fno-commoncommonbss

于 2013-05-30T12:26:31.637 に答える