1

次の C 標準からの抜粋に示されている C のリンク規則については承知しています。

1/ 異なるスコープまたは同じスコープで複数回宣言された識別子は、リンケージと呼ばれるプロセスによって同じオブジェクトまたは関数を参照することができます。リンケージには、外部、内部、およびなしの 3 種類があります。

2/ プログラム全体を構成する翻訳単位とライブラリのセットでは、外部リンケージを持つ特定の識別子の各宣言は、同じオブジェクトまたは関数を示します。1 つの翻訳単位内で、内部リンケージを持つ識別子の各宣言は、同じオブジェクトまたは関数を表します。リンクのない識別子の各宣言は、一意のエンティティを示します。

3/ オブジェクトまたは関数のファイル スコープ識別子の宣言にストレージ クラス指定子 static が含まれている場合、識別子には内部リンケージがあります。

4/ ストレージ クラス指定子 extern を使用して宣言された識別子が、その識別子の前の宣言が可視であるスコープ内で宣言されている場合、前の宣言が内部リンケージまたは外部リンケージを指定している場合、後の宣言での識別子のリンケージは、事前宣言で指定されたリンケージ。前の宣言が表示されない場合、または前の宣言でリンケージが指定されていない場合、識別子には外部リンケージがあります。

5/ 関数の識別子の宣言にストレージ クラス指定子がない場合、そのリンケージは、ストレージ クラス指定子 extern で宣言されているかのように正確に決定されます。オブジェクトの識別子の宣言にファイル スコープがあり、ストレージ クラス指定子がない場合、そのリンケージは外部です。

6/ 次の識別子にはリンケージがありません。オブジェクトまたは関数以外のものとして宣言された識別子。関数パラメーターとして宣言された識別子。ストレージ クラス指定子 extern なしで宣言されたオブジェクトのブロック スコープ識別子。

7/ 翻訳単位内で、同じ識別子が内部リンケージと外部リンケージの両方で表示される場合、動作は未定義です。

extern キーワードはデフォルトで外部であるため、関数宣言の前にオプションであることを理解していますが、stdlib.h には次のような extern が前にある関数プロトタイプがいくつかあります。

extern void qsort (void *__base, size_t __nmemb, size_t __size,
           __compar_fn_t __compar) __nonnull ((1, 4));

また、関数と変数に関して、gcc がポイント 7 で説明されている状況を異なる方法で処理する理由。この例では、関数 foo と変数 d の両方が内部スコープと外部スコープの両方で定義されていますが、変数定義のみがエラーを発生させます。

static int foo(void); 
int foo(void); /* legal */

static double d;
double d; /* illegal */
4

1 に答える 1

0

関数宣言の前に extern を配置するかどうかは自由に指定できるため、どこかに extern があることは驚くべきことではありません。2番目の質問について:

C11 ドラフト (n1570.pdf) の 159 ページには、暫定的な定義に関連する例があります。

static int i5; // tentative definition, internal linkage
// ...
int i5; // 6.2.2 renders undefined, linkage disagreement
extern int i5; // refers to previous, internal linkage

6.2.2はあなたが投稿したものです。したがって、リンクの異なる 2 つの仮定義が存在するため、この場合は機能しないため、p.7 違反があります。一方、p.4が強制されるため、外部指定子(例のfoo関数として)で機能します-後の宣言は、最初の宣言で定義されたリンケージを参照します。つまり、変数はオブジェクトであり、暫定的な定義規則が含まれているため、変数のケースは機能しません。少なくとも標準には、委員会が言いたかったことを明確に説明する明示的な例が含まれています。

于 2013-10-05T17:56:00.997 に答える