一、问题引出
当多个源文件链接在一起,我们如何处理相同名字的标识符?假设多个源文件均含有变量a,那么它的值到底采用哪个源文件定义的值呢?这就涉及到标识符的链接属性。
二、对象
链接属性针对标识符而言,对象通常是变量、函数名、形参。
三、分类
链接属性(linkage)分为三种——外部(external)、内部(internal)、无(none)
3.1 外部(external)
判别依据
//demo0.c
#include <stdio.h>
int x;
int func(int a){
int y;
}
- 在demo0.c中,x、func具有external的链接属性,简而言之,并非声明于代码块内的变量,缺省情况下具有external链接属性,(函数名也不包含于任何代码块)。
//demo1.c
int x = 10; #include <stdio.h>
void print(void) int main(void)
{ {
printf("Hello World!\n"); extern int x;
} printf("%d ");
print();
return 0;
} //demo2.c
- 在文件A中具有external链接属性的变量(或函数名)具有全局可见性,对于变量,在声明前加extern表示引用文件A中的对应变量,函数则可以直接使用。
- 当用于具有文件作用域的声明时,这个关键字是可选的。然而,如果你在一个地方定义变量,并在使用这个变量的其他源文件的声明中添加external关键字,可以使读者更容易理解你的意图
- 例如demo1.c中x和print具有external链接属性,在demo2.c中,extern int x表示这里的x就是demo1.c中的x,这里的x链接属性就是external,print就是demo1.c中的print 。
3.2 内部(internal)
判断依据
//demo3.c
#include <stdio.h>
static int x;
static int func(int a){
int y;
}
- 缺省情况下,除了上述说明的external属性以外,其余均为none。因此internal属性出现在static修饰之后。
- demo3.c中,如果删除static,则和demo0.c相同,即x和func在原先属于external,在用static关键字修饰之后则有了internal属性,即只能够在demo3.c一个文件中访问,其他文件不能访问。
//demo4.c
static int x = 10; #include <stdio.h>
static void print(void) int main(void)
{ {
printf("Hello World!\n"); extern int x;
} printf("%d ");
print();
return 0;
} //demo5.c
- 上述两个程序不能成功链接。当具有external属性的变量(或函数名)用static关键字修饰之后,就具有了internal链接属性,其他文件不能访问它们。因此,demo5.c中extern int x; 和 print(); 是错误的,因为x和print不再是external的链接属性了。
- 不要用static关键字修饰none属性的标识符,对于链接属性,static只能修改external属性的标识符,若修饰none属性的,改变的是存储类型而非链接属性。
3.3 无(none)
判断依据
//demo6.c
#include <stdio.h>
int x;
int func(int a){
int y;
}
- 在demo6.c中,a和y具有none的链接属性,简而言之, 函数形式参数和代码块内声明的变量在缺省情况下具有none链接属性 。
- none链接属性标识符仅允许作用域内访问。
3.4 static关键字
当用于不同的上下文环境时,static关键字具有不同的意思。确实很不幸,因为这总是给C程序员新手带来混淆。本节对static关键字作了总结,再加上后续的例子程序,应该能够帮助你搞清这个问题。
当它用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的链接属性,从external改为internal,但标识符的存储类型和作用域不受影响。用这种方式声明的函数或变量只能在声明它们的源文件中访问。
当它用于代码块内部的变量声明时,static关键字用于修改变量的存储类型,从自动变量修改为静态变量,但变量的链接属性和作用域不受影响。用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一直存在,而不是每次在代码块开始执行时创建,在代码块执行完毕后销毁。
四、Tips
- 链接属性的改变不会改变作用域(scope)。
- 链接不是 #include,不能直接 #include”demox.c” 来链接不同的源文件,否则会得出不同结论,链接方式多样,我用的是gcc命令,gcc -o filename file1.c file2.c 。
- 链接属性最好和作用域、存储类型一起学习(static关键字涉及了三者),这篇博文主要内容是链接属性。
- 上述程序范例很相似,可以通过寻找不同处来理解链接属性。
- 链接属性不仅意味着能不能访问变量,也意味着能不能在文件中定义同名变量或函数名。
- 当extern关键字用于源文件中一个标识符的第1次声明时,它指定该标识符具有external链接属性。但是,如果它用于该标识符的第2次或以后的声明时,它并不会更改由第1次声明所指定的链接属性。