[C]链接和生存周期
链接和生存周期的区别:
- 链接是标识符的属性;
- 生存周期是对象的属性;
- 链接可以是外部(external),内部(internal)或没有(none);
- 生存周期可以是自动的、静态的,或已分配的(allocated);
链接:
一个被声明在多个翻译单元内的标识符,或者在同一个翻译单元内被声明多次的标识符,可以每次指向相同的对象或函数。如示例4,具有外部链接的变量,引用的都是同一个对象;
如果该标识符具有链接,那么它和其他跟它一样具有相同链接的标识符共享一个对象或函数;
只有对象和函数标识符可以有外部或内部链接!所以一些预处理指令不能跨编译单元访问;
| 概念 | 概念 | 属于该状态的声明 | 例外 | 关于隐藏 |
| 外部链接 | 具有外部链接的标识符,表示整个程序内都是相同的函数或对象。编译器会将这种标识符交给连接器(linker),由链接器解析(resolve)这类标识符,并且把其他翻译单元和链接库中的相同标识符链接起来。 |
函数外部使用了不带存储修饰符的函数和对象标识符; 函数外部使用了extern存储修饰符的函数和对象标识符(事实上这是一个不规范的写法,如果你明确这个变量需要被外部引用,最好就是不带任何存储修饰符,如果必要这样做,你需要写成这样示例3); 函数内部带extern的对象,而这个对象在外部具有外部链接; |
如果标识符已经被声明为内部链接,在第一次声明的作用域内做第二次声明,并无法将此标识符的链接变成外部链接,这种情况处在翻译单元内和处在翻译单元外的表现又有不同: |
倘若其他翻译单元中定义了一个外部链接,那么就不能在 此单元内再定义一个外部链接,否则在编译器链接单元阶段会报错; |
| 内部链接 |
“内部链接的标识符”代表在此翻译单元内是“相同的对象或函数” 。此标识符不会被链接器(linker)处理。因此,你无法在别的翻译单元中使用此标识符,以指向到相同的对象或函数。 具有内部链接的标识符,不会和其他翻译单元内类似的标识符产生冲突(示例5)。然而,如果某个标识符在某翻译单元内具有外部链接,你就无法在该翻译单元内声明此标识符是内部链接的。或者,换句话说,如果在某个翻译单元内声明某个标识符是内部链接,就无法声明和使用另一个翻译单元中“同名称”的外部标识符。 |
非函数内部,使用static存储修饰符声明的函数或对象; 函数内部带extern的对象,而这个对象在外部具有内部链接(参考示例1 的变量e); |
在其他翻译单元具有外部链接的情况下在此单元声明一个内部链接,则此单元隐藏外部链接,在此单元内使用内部链接(示例6) | |
| 无链接 | 如果标识符不是外部链接,也不是内部链接,它就是无链接的。每出现这种标识符的声明,就会多出一个新的实体(entity),也就是编译器需要在内存上创建一个单独的对象仅供此标识符使用。 |
不是变量名称,也不是函数名称的标识符,比如卷标名称(label name)、结构小标签(tag)和typedef名称; 函数参数; 被声明在函数内,并且没有extern修饰符的对象标识符(包含被声明为static的标识符); |
示例1:
int func1(void); // func1具有外部链接。
int a; // a具有外部链接。
extern int b = ; // b具有外部链接。
static int c; // c具有内部链接。
static int e; // e具有内部链接。 static void func2(int d) // func2 具有内部链接; d具有无链接。
{
extern int a; // 此a和上面一样,具有外部链接。
int b = ; // 此b具有无链接,并且将上面声明的b隐藏起来 extern int c; // 此c和上面一样,维持内部链接。 static int e; // e具有无链接,并且将上面声明的e隐藏起来。 int f; // f具有无链接 }
示例2:
//翻译单元A
static int foo = ;
//翻译单元B
#include <stdio.h> extern int foo;
void main(void)
{
printf("%s:foo:%d\n", __func__, foo);
}
在链接两个编译单元的时候,编译器会抛出错误:
undefined reference to `foo'
示例3:
//直接初始化带extern的对象,编译器会发出警告
extern int foo = ;
//this is recommend.
extern int foo;
int foo = ;
示例4:
//翻译单元A声明变量foo
int foo = ;
//翻译单元B定义一个修改foo的函数
void func1(void)
{
extern int foo;
foo = ;
}
//翻译单元C调用函数修改了foo,并且输出
#include <stdio.h> extern void func1(void); void main(void)
{
func1();
extern int foo;
printf("%s:foo:%d\n", __func__, foo);//输出2048
}
示例5:
//翻译单元A声明一个具有内部链接的foo
static int foo = ;
//翻译单元B声明一个具有外部链接的foo,并且让翻译单元C修改这个foo
#include <stdio.h> extern void func1(void);
int foo = ; void main(void)
{
func1();
printf("%s:foo:%d\n", __func__, foo);//输出2048
}
//翻译单元C声明一个修改外部foo的函数
void func1(void)
{
extern int foo;
foo = ;
}
示例6:
//翻译单元A声明一个外部链接
int foo = ;
//翻译单元B
#include <stdio.h> void func1(void);
void func2(void);
static int foo = ; void main(void)
{
printf("%s:foo:%d\n", __func__, foo); //输出1
func1();
printf("%s:foo:%d\n", __func__, foo); //输出2048
func2(); //函数内输出1024,即单元以外的foo还是沿用外部链接那个foo
} void func1(void)
{
extern int foo; //foo具有翻译单元作用域,所以就算这里省略掉extern int foo;声明,也可以正常访问到foo
foo = ;
}
//翻译单元C
#include <stdio.h> void func2(void)
{
extern int foo;
printf("%d\n", foo);
}
生存周期:
对于理解对象生存周期则简单许多,只需要记住以下几点:
| 生存周期 | 描述 | 情况 |
| 进程(静态)生存期 |
对象会一直存在,直至进程结束; brk()划分的空间直到手动调用调用free()才会释放,否则直至进程结束; |
函数外声明的对象; 函数内带static关键字的变量; 函数内带内/外部链接的变量; 通过brk()划分的内存空间,例如malloc()、calloc()、realloc(); |
| 栈(自动)生存期 | 对象会存在到栈退出 | 函数自变量; |
[C]链接和生存周期的更多相关文章
- CLR和.Net对象生存周期
标签:GC .Net C# CLR 前言 1. 基础概念明晰 * 1.1 公告语言运行时 * 1.2 托管模块 * 1.3 对象和类型 * 1.4 垃圾回收器 2. 垃圾回收模型 * 2.1 为什么需 ...
- 关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题
在进入正题前我们必须了解一些概念: 标识符:标识符不仅仅代表着变量的名字,main()函数的main也是一个标识符,这点很重要. 存储类型:即变量的存储位置及其生存周期:静态区:分为两块 .date ...
- C Primer Plus之存储类、链接和内存管理
存储时期即生存周期——变量在内存中保留的时间 变量的作用域和链接一起表明程序的哪些部分可以通过变量名来使用该变量. 注意:生存期和作用域是两个不同的概念. 作用域 作用域描述了程序中可以访问一个 ...
- [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结
来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...
- C语言存储类别和链接
目录 C语言存储类别和链接 存储类别 存储期 五种存储类别 C语言存储类别和链接 最近详细的复习C语言,看到存储类别的时候总感觉一些概念模糊不清,现在认真的梳理一下.C语言的优势之一能够让程序员恰 ...
- python+uwsgi导致redis无法长链接引起性能下降问题记录
今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...
- vs2010静态链接MFC库报链接错误
由于需要将MFC程序在其它电脑上运行,所以需要将动态链接的MFC改成静态链接,本以为很简单,没想到链接的时候出现下面的链接错误: uafxcw.lib(afxmem.obj) : error LNK2 ...
- Mach-O 的动态链接(Lazy Bind 机制)
➠更多技术干货请戳:听云博客 动态链接 要解决空间浪费和更新困难这两个问题最简单的方法就是把程序的模块相互分割开来,形成独立的文件,而不再将它们静态的链接在一起.简单地讲,就是不对那些组成程序的目标文 ...
- 菜鸟在C语言编译,链接时可能遇到的两个问题
最近在看 CSAPP (Computer Systems A Programmers Perspective 2nd) 的第七章 链接.学到了点东西,跟大家分享.下文中的例子都是出自CSAPP第七章. ...
随机推荐
- Selenium之勾选框操作
勾选框操作: 所谓勾选框,意思是可以勾选一个及以上或全部勾选.勾选框的图标一般都是方形的. 复选框勾选一般分为三种情况: ①勾选单个框,我们直接用元素定位的方式定位到点击即可. ②勾选多个 ...
- usb2.0高速视频采集之68013A寄存器配置说明
任何的固件编程离不开与与原理图参考,图纸中所采用的是USB的Slave_fifo传输方式,具体配置与图纸对应即可. •USB_IFCLK:同步Slave_FIFO模式,输入频率范围5M-48M,在FP ...
- 350. 两个数组的交集 II
给定两个数组,编写一个函数来计算它们的交集. 示例 1: 输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2,2] 示例 2: 输入: nums1 = [4,9,5 ...
- MySQL 05
目录 事务 基本概念 四大特性(ACID) 使用方法 存储引擎 视图 基本概念 使用方法 触发器 基本概念 使用方法 存储过程 基本概念 使用方法 数据备份 备份 导入 函数 事务 基本概念 事务: ...
- redis(5)--redis集群之哨兵机制
哨兵机制 在前面讲的master/slave模式,在一个典型的一主多从的系统中,slave在整个体系中起到了数据冗余备份和读写分离的作用.当master遇到异常终端后,需要从slave中选举一个新的m ...
- 【CentOS7】curl命令
[CentOS7]curl命令 转载: 参考 https://www.thegeekstuff.com/2012/04/curl-examples/ http://www.cnblogs.com/gb ...
- 【Visual Studio Code】插件
[Visual Studio Code]插件 转载:https://www.cnblogs.com/yangchongxing/p/10625628.html 目录 ================= ...
- 面试完腾讯,总结了这12道Zookeeper面试题!
前言 ZooKeeper 是一个开源的分布式协调服务,可以基于 ZooKeeper 实现诸如:数据发布/订阅.负载均衡.命名服务.分布式协调/通知.集群管理.Master 选举.配置维护,名字服务.分 ...
- 函数基础重点掌握内容:创建函数、return返回单个值、return返回多个值、函数名加括号与不加括号的区别
##比较两个数大小 #有参函数!!! def compare(s,t): if s > t: print(s) else: print(t) f=compare compare(1000,30) ...
- 牛客NOIP暑期七天营-提高组5+普及组5
————提高组———— 第一题:deco的abs 题目链接:https://ac.nowcoder.com/acm/contest/934/A 因为每个数都可以加任意次 d ,所以可以推出 0 < ...