返回

C语言链接和存储类型(15)

发布时间:2023-12-13 15:13:22 323

链接概念

链接是C语言程序编译的一个步骤,就是对程序中引用的外部变量或函数(例如标准库中定义的变量或函数)进行解析,将它们的定义包含到C语言程序中,形成一个完整的可执行程序。

例如:C语言中程序声明了a,b,c三个变量和func函数,其中a,b变量定义均在当前文件中,变量c和函数func是引用其他库或文件中的定义中,链接会将c变量定义和func函数定义信息合并到当前程序,形成完整的程序。

C语言链接分为三类,让在不同作用域的标识符或同一作用域的标识符引用相同的对象或函数。

•外部链接:不同源文件引用相同的对象(变量)或函数,使用extern修饰的变量或函数

•内部链接:在同一个源文件中引用相同的对象或函数,使用static修饰的具有文件作用域的变量或函数

•无链接:非对象(变量)或函数的标识符;函数形参的标识符;具有块作用域的且无extern修饰的标识符

存储类型分类

存储类型指明变量的存储空间分配位置和变量的生命周期。C语言规定了

auto、register、extern、static四种存储类型区分符,用于在变量类型前面修饰。

1.auto

块作用域的局部变量,默认是auto自动类型,该类型的变量在进入块或函数时,自动在栈上分配空间,出块或函数返回时释放空间。

auto类型只能修饰局部变量。

例如:

{
int a = 100;
auto int a = 100; // 两者等价
}
2.register

修饰变量时表示该变量寄存器类型,指导编译器尽量将变量存放到寄存器,以加快访问速度,寄存器类型变量无法使用&获取地址;也无法使用寄存器类型数组名转换成指针。

•不能修饰函数、不能声明全局变量

•只能声明块作用域的局部变量、函数参数

•编译器不能保证一定会将变量分配到寄存器,也可以使用auto分配

例如:

register int a = 100;  // register修饰全局变量,不合法
void func(void){
register int b = 200;
int *p = &b ; // 取地址运算,不合法

register int c[100];
int *p = c; // 数组名转换指针,不合法
}
3.extern

外部类型,可以修饰变量或函数,作用域与具有文件作用域的普通变量或函数一样,如果当前文件无该变量或函数的定义时,编译器使用外部链接,链接到其它文件提供的该变量或函数的定义。

:函数声明如果未指明存储类型,默认是extern类型

例如:

// 函数定义在其它文件或库中
extern int sum(int a, int b);

// 等价上面
int sum(int a, int b);

// 变量定义和初始化在其它文件或库中
extern int i;

例如:

main.c源文件:

#include 
extern int sum(int a, int b);
int add(int a, int b);
extern int res;
int main(void) {
printf("%d %d %d\n", sum(100,100), add(100,100),res);
return 0;
}

test.c源文件:

int res =100;
int sum(int a, int b){
return a+b;
}
int add(int a, int b){
return a+b;
}

输出:​​200 200 100​

4.static

静态类型,可以修饰变量或函数。

修饰函数 表示该函数必须是当前文件声明定义的,也只能在当前文件中使用,不使用外部链接去链接其它库或文件中函数定义,也不被其他文件链接。

修饰全局变量表示该变量是文件作用域,定义和作用在当前文件中,不被其他文件链接,也不能链接其他文件。

例如:示例1,test.c中的变量和函数不能被main.c文件链接使用。

main.c源文件:

# include 
extern int sum(int a, int b);
extern int res;
int main(void) {
printf("%d %d\n", sum(100,100), res);
return 0;
}

test.c源文件:

static int res = 100;
static int sum(int a, int b){
return a+b;
}

输出:编译错误,提示找不到sum函数定义和变量res定义。

例如:示例2,main.c中的变量和函数不能链接其他文件test.c中定义的变量和函数。

main.c源文件:

# include 
static int sum(int a, int b);
static int res;
int main(void) {
printf("%d %d\n", sum(100,100), res);
return 0;
}

test.c源文件:

int res = 100;
int sum(int a, int b){
return a+b;
}

输出:编译错误,提示sum函数未定义。

修饰局部变量,表明该变量会在程序的静态内存空间分配,该变量在程序开始执行前分配空间和初始化,不会每次进入或作用域重新分配空间和初始化,一直到程序退出释放空间。使用static修饰的局部变量只会初始化一次。

例如:

# include 
int test(){
static int i = 0;
i++;
return i;
}
int main(void) {
printf("%d\n", test());
printf("%d\n", test());
printf("%d\n", test());
printf("%d\n", test());
return 0;
}
输出:
1
2
3
4

分析:static局部变量只会初始化一次以后每次调用都会在原来的值基础+1,不会释放。

------------ End ------------

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
常量 2023-12-13 11:57:24