C 链接属性浅析
链接属性用于处理多个文件中同名标识符是否指向同一实体的问题。C 中有三种链接属性——None,Internal和External。让我们分别看看这三种类型。
- None:表示该标识符没有其他链接,总是独立的。也就是说这些标识符都会指向独立的、不同的实体
- Internal:表示在同一文件中声明的标识符都会指向同一实体,而不同文件中声明的同名标识符则会指向其他实体
- 换言之,它修饰的变量仅能在本文件使用,其他文件无法访问
- External:表示无论在哪声明该标识符,也无论声明多少次,它们都会指向同一实体
- 换言之,它修饰的变量可以引用其他文件中定义的变量
代码分析
看下代码就明白三者的不同了:
None
//FileOne.c
void foo()
{
int var;
}
//FileTwo.c
void func()
{
int var;
}
局部变量就是一个很好的例子。这两个变量虽然同名,但会被独立的处理开来,它们指向的是不同的实体。
Internal
该类型的链接需要static关键字修饰。
//FileOne.c
static int var = 0x7f;
var只能在FileOne中被使用,其他文件无法访问此变量。也就是说,FileOne中声明的所有var都将指向同一个实体,而其他文件中声明的var将指向不同实体。
External
该类型需要使用extern关键字修饰
//FileOne.c
int var = 123;
//FileTwo.c
extern int var; //TIP : 这是声明语句,而非定义语句。声明语句不会申请新空间,而定义会
printf("%d",var); //123
可见FileTwo文件声明的同名标识符var也指向了同FileOne一样的实体。
变量所属链接属性的判别
这里有几个基本的准则:
- 具有代码块作用域或函数原型作用域的变量属于None链接属性
- 如函数中的局部变量
- 全局变量(函数等)默认拥有external链接属性
- 变量一经定义其链接链接属性就不能被改变
对于第二点我们举例说明一下:
//FileOne.c
int a = 123;
//FileTwo.c
#include <stdio.h>
#include <stdlib.h>
/**
* 全局变量默认具有external链接属性,实际上此句话等价于:
* extern int a;
* */
int a;
int main()
{
printf("%d",a);//123;
return EXIT_SUCCESS;
}
此外有个特殊的情况需要注意一下:
int main()
{
extern int b;
int b = 456;
}
对于这种同作用域下对同变量施加不同链接属性的情况,在笔者Mac中的Eclipse下无法通过编译,提示“ non-extern declaration of ‘b’ follows extern declaration”。即使这两个语句调换一下也有不可以。笔者后在网上找到了对此情况的说明:
Two declarations of a in the same scope with different linkage give undefined behaviour.
在同作用域中,声明两个具有不同链接属性的变量a将导致未定义行为。
因此应避免这类情况的发生。