C++—19、C++ 中静态存储static

今天来介绍c++中的static关键字,根据上下文有两种意思,一种是在类class或者结构体外使用static;另一种是在类class或者结构体内使用。总结一下:类外的static修饰的符号在link阶段是局部的,也就是它只对定义它的编译单元(.obj)可见。而类和结构体里面的static,表示这部分内存是这个类的所有实例共享的,简单来说,就算你实例化了很多次这个类或结构体,但那个静态(static)变量只会有一个实例(就是只有一个),类里面的静态方法也是一样,静态方法里没有该实例的指针(this)。之后会更详细的讲static在类或结构体里的意思—作用域(scope)。

一、类或者结构体外的static

1、正确使用static的方式

我们在一个static.cpp文件里面,只定义一个static变量。

除了前面的static,它看起来就跟普通的变量一样。这个static什么意思呢?它表示这个变量在link的时候只在这个编译单元(.obj)里可见。

(如果你不清楚c++的编译和链接link的原理,这里简要叙述下。

第一步:预处理

C/C++语言最常见的预处理就是将所有的“#define”删除,并且展开所有的宏定义。而预处理其实还包括:处理所有的条件编译指令,比如“#if”、处理“#include”预编译指令、删除所有的注释、添加行号和文件名标识等。

第二步:编译

编译会将源代码由文本形式转换成机器语言,编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。

编译后的.s也是ascii码文件。因为汇编也是人能看懂的文字编码形式,所以.s汇编文件也是ASCII码文件。

第三步:汇编

汇编过程调用汇编器AS来完成,是用于将汇编代码转换成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。(非底层的程序员不需要考虑)

汇编后的.o文件是纯二进制文件。因为.o中放的是纯二进制的机器指令,所以我们打开后看不懂。
ASCII的源码被汇编为能被CPU执行的机器指令,.o文件中放的就是机器指令。但是.o文件还无法运行,需要链接后才能运行。

第四步:链接

链接是将所有的.o文件和库(动态库、静态库)链接在一起,得到可以运行的可执行文件(Windows的.exe文件或Linux的.out文件)等。它的工作就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定向。

static变量或者函数表示在link到它实际的定义时,linker不会在这个编译单元.obj外面找它的定义。我们来看另一个cpp文件(也就是另一个编译单元),这儿是main函数的cpp文件。我们创建一个跟前面静态变量名字一样的全局变量并赋值为10,然后输出它。

发现没有任何问题。

2、没使用static导致变量的重复定义

当我们把static.cpp文件里的static去掉。编译运行发现有一个重复定义的变量,如下图:

可以看到在linking阶段有个link错误。因为s_Variable已经在另一个编译单元里定义了,所以两个全局变量的名字不能一样。

3、如何使用另外cpp文件中的变量-extern

一种解决办法是把这个变成另一个的引用,就是把赋值去掉再加上extern关键字如下图:

加上extern关键字,它就会在另外的编译单元里找s_Variable的定义,这被称为external linkage或者external linking,这样运行代码就正常了。因为他是static.cpp文件中变量的引用。

但是加入我在变量声明前面加上static,那外部就找不到了,如下图:

这有点像在class里面声明私有(private)成员,其他的编译单元不能访问s_Variable。

linker在全局作用域下找不到它,所以就出现了上面的无法解析的外部符号,也就是因为linker在任何地方都找不到s_Variable的定义,因为我们把这个变量标记成了“私有”的。

4、函数和变量情况是一样的

和之前一样,我们来声明一个函数。

main里面也声明了个有同样签名、没有返回值的函数。

调试就会发现,多了一个错误,在链接阶段就出现错误重复定义。如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Growthofnotes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值