标识符的链接
不同作用域内或者相同作用域内多次声明的标识符通过链接(linkages)可以指向相同的对象或者函数(注:不同标识符之间没有链接。)。C语言中标识符存在3种形式的链接:内部链接(internal linkage)、外部链接(external linkage)、无链接(no linkage)。
在构成整个程序的编译单元和库中,每个具有外部链接的同名标识符的声明都表示相同的对象或者函数。在同一编译单元中,每个具有内部链接的同名标识符的声明都表示相同的对象或者函数。无链接标识符的每次声明都表示一个唯一的实体。
标识符的链接形式由其声明位置以及声明中使用的存储类说明符(storage-class specifiers)共同决定。C语言中只有对象标识符和函数标识符具有内部链接或者外部链接。
一、内部链接
具有文件作用域的对象如果在声明中使用了存储类说明符static或者constexpr,以及具有文件作用域的函数如果在声明中使用了存储类说明符static,那么该对象或者函数具有内部链接。
static int number; static int func(int); constexpr int *ptr = nullptr; int main(void) { ... }
变量number、函数func、指针ptr都具有内部链接。
具有内部链接的相同标识符在同一编译单元内表示相同的对象或者函数。
static int value; void func(void) { extern int value; ... }
两次声明中的value标识符都具有内部链接,它们表示相同的对象。
二、外部链接
如果一个对象标识符声明时具有文件作用域,并且没有存储类说明符static或者constexpr,那么该标识符具有外部链接。
int number; int main(void) { ... }
变量number是具有文件作用域的对象标识符,具有外部链接。
如果函数标识符的声明没有存储类说明符,其链接与使用存储类说明符extern声明的情况完全相同。
标识符声明使用了extern存储类说明符,如果先前声明的标识符可见,并且先前声明指定了内部链接或者外部链接,该标识符与先前声明具有相同的链接;如果没有可见的先前声明或者先前声明无链接,该标识符具有外部链接。
int number; //number具有外部链接。 static int value = 8; //value具有内部链接。 int main(void) { { int data = 10; } extern int number; //number具有外部链接。 extern int value; //value具有内部链接。 extern int data; //data具有外部链接。 ... }
使用extern存储类说明符声明的标识符number和value在先前声明的作用域内;但标识符data不在先前声明的作用域内。
具有外部链接的相同标识符在整个程序中表示相同的对象或者函数,例如:first.c和second.c两个文件构成的程序,代码如下所示:
/* first.c*/ #include <stdio.h> #include "second.c" int number; int main(void) { printf("number = %d\n", number); return 0; }
/* second.c*/ int number = 10;
first.c文件中的标识符number和second.c文件中的标识符number表示相同对象。
在同一编译单元内,如果相同标识符既有内部链接,又有外部链接,其行为是未定义的。
三、无链接
C语言中无链接标识符包括以下3种情况:
① 除对象标识符和函数标识符以外的标识符,例如:typedef名;
② 声明为函数形式参数的标识符;
③ 具有块作用域,未使用extern存储类说明符声明的对象标识符。
typedef int Day; //Day为无链接标识符。 void func(int number); //number为无链接标识符。 int main(void) { int value; //value为无链接标识符。 ... }
Day为typedef名,number为函数形式参数,value为具有块作用域且未使用extern声明的对象标识符;Day、number、value都是无链接标识符。
主要参考资料:
3、《C语言程序设计 现代方法》第2版•修订版 作者:K.N.King 出版社:人民邮电出版社
4、learn.microsoft.com : No Linkage