7

C

次のCモジュールがあるとします。

モジュール1

#include <stdio.h>
int x;
int main(){
  foo();
  printf("%i\n",x);
  return 0;
}

モジュール2

double x;
void foo(){
  x = 3.14;
}

私の質問は、この場合、リンカーは何をするのかということです。私が読んでいる教科書では、コンパイラがリンカーシンボルテーブルに2つの弱いグローバル変数のうちの1つだけを選択すると書かれています。この2つのうちどちらが選ばれますか?それとも両方が選ばれますか?もしそうなら、なぜですか?ありがとう。

4

2 に答える 2

6

Cはそれが未定義の振る舞いであると言います。

(C99、6.9p5)「外部リンケージで宣言された識別子が式で使用される場合(結果が整数定数であるsizeof演算子のオペランドの一部として以外)、プログラム全体のどこかに、外部が1つだけ存在する必要があります。識別子の定義。それ以外の場合は、1つしか存在しないものとします。」

未定義の動作であるということは、リンカが複数の外部オブジェクト定義の存在下でリンクプロセスを中止できることを意味します。

現在、リンカーは優れており(またはであり、選択できます)、通常、複数の外部オブジェクト定義を処理するためのデフォルトの拡張機能があり、場合によっては失敗しません。

binutilsを使用gccldている場合、2つのオブジェクトが明示的に初期化されていると、エラーが発生します。たとえばint x = 0;、最初の翻訳単位にとがありdouble x = 0.0;ます。

それ以外の場合、外部オブジェクトの1つが明示的に初期化されていない場合(この例の状況)gcc、2つのオブジェクトがサイレントに1つのシンボルに結合されます。オプションを渡すことで、リンカーに警告を報告するように依頼することもできます--warn-common

たとえば、モジュールをリンクする場合:

gcc -Wl,--warn-common module1.o module2.o

--fatal-warningsリンクプロセスを中止するには、オプション( )を使用して、すべての警告をエラーとして処理するようにリンカに要求できます-Wl,--fatal-warnings,--warn-common

リンクプロセスを中止する別の方法は、 @ teppic-fno-commonの回答で説明されているように、コンパイラオプションを使用することです。外部オブジェクトがコンパイル時に共通シンボルタイプを取得することを禁止します。モジュールとリンクの両方に対してこれを行うと、複数定義リンカーエラーも発生します。-fno-common

gcc -Wall -fno-common -c module1.c module2.c

gcc module1.o module2.o

于 2013-03-24T21:34:42.110 に答える
1

実装が複数の外部定義をサポートしている場合、ある種の暗黙的な共用体変数のように、各モジュールの各型に効果的にキャストされる1つのオブジェクトになります。より大きなタイプのメモリの量が割り当てられ、両方が外部宣言として動作します。

clangまたはgccを使用してコンパイルする場合は、このオプション-fno-commonを使用してエラーを発生させます。

gccマニュアルのセクションは次のとおりです。

       In C code, controls the placement of uninitialized global
       variables.  Unix C compilers have traditionally permitted multiple
       definitions of such variables in different compilation units by
       placing the variables in a common block.  This is the behavior
       specified by -fcommon, and is the default for GCC on most targets.
       On the other hand, this behavior is not required by ISO C, and on
       some targets may carry a speed or code size penalty on variable
       references.  The -fno-common option specifies that the compiler
       should place uninitialized global variables in the data section of
       the object file, rather than generating them as common blocks.
       This has the effect that if the same variable is declared (without
       "extern") in two different compilations, you will get a multiple-
       definition error when you link them. 

このオプションは、複数の定義に関して厳密なISOC準拠を効果的に実施します。

この動作は、通常、同じタイプの外部変数で受け入れられます。GCCマニュアルに記載されているように、ほとんどのコンパイラはこれをサポートしており、(タイプが同じであれば)C99標準はその使用を拡張として定義しています。

于 2013-03-24T22:42:21.783 に答える