次の 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 */