我知道 C 标准的以下摘录中提出的 C 链接规则:
1/ 在不同范围内或在同一范围内多次声明的标识符可以通过称为链接的过程来引用同一对象或函数。有三种联系方式:外部、内部和无。
2/ 在构成整个程序的一组翻译单元和库中,具有外部链接的特定标识符的每个声明都表示相同的对象或函数。在一个翻译单元中,具有内部链接的标识符的每个声明都表示相同的对象或函数。没有链接的标识符的每个声明都表示一个唯一的实体。
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 */