C语言 static 声明静态变量?大佬原来用它干这事!

C语言可变参数只会用算啥本事?看我来抽丝剥茧干翻它!

高手在写代码的时候,会特别注重的一点就是,对外的方法对外,不对外的方法和数据,都是让其对外不可见,也就是俗称的,内部不想让别人直接访问的方法,变量,就不要让其可以访问到,从而保证几点:

1 不污染全局符号

2 数据和方法保证不被不规范的引用

而C语言中的关键字 static 就是起这个作用,我们这节来讲讲这个玩意。再说这个前,我想跟大家先讲一个内容,之前也说过。

代码段

数据段

BSS段



代码段是只读区域,这个段落不允许修改,加载时候会指定只读。

数据段分为,只读区域和可变区域。只读区域就是类似于常量数据,还有常量字符串这些,同时还有一些使用const 关键字修饰的,会放到这里,标记只读,保证数据不会被随意修改。

BSS段放置的是全局的未初始化的变量,这个编译成可执行文件因为没有初始化数据,所以可执行文件中就不占大小,但是如果初始化了,就会占大小。

堆,我们使用 malloc 申请内存空间,就是在这个区域,这个区域是需要主动去释放空间,否则会内存泄漏。

栈,函数内部的局部变量,以及函数之间调用,临时使用的空间,这个是依赖栈的压入,弹出机制,重复在用。(这里用一个网上图片,大家一目了然)

栈我们一般不用关注,它会自动平衡,但是我们一般在栈里面要考虑的就是栈溢出。栈也是有大小的,系统会分配一段区域,用在压栈,弹出操作,如果你两个函数相互调用,就会出现栈溢出。

为什么要说这个?其实就是因为 static 关键字,有一个功能,就是会让局部变量本该在栈上,用这个声明后,就会进入全局区域,也就是从栈区域,进入到数据区域。

下面我们来看下代码:add.c

hello.c

我们这里看下,没有#include “add.h”, 我们使用 

gcc -o add.o -c add.c

gcc -o hello.o -c hello.c

gcc -o hello hello.o add.o

发现是可以编译过,也能链接过,也能运行。我们使用readelf -s add.o ,看到信息,add前面有个Bind的值是GLOBAL,这个就是说明,add是在可以让其他.o链接时候去查找的一个符号,它的类型是func函数。

然后我们把add.c 改成这个:(前面加上一个static)

编译链接就会失败,找不到add方法,那么我们readelf -s add.o再看下:

add前面Bind的值变成了LOCAL,这时候对外就不可见了。这也就是static在全局的时候,起的作用,将对应的变量,或者函数的可见范围,变成只对自身可见,对外不可见。

这个是为了降低重名的几率,也是防止自身的全局变量被外部访问,瞎修改的风险。

为了说明这个情况,我们来演示下这个过程,add.c改成这样:

hello.c 改成

编译执行后,最终结果输出17,是不是让我们一下子就不明白,a b两个值被外部随意修改,导致没法看懂代码业务。

我们看到有两个类型是 OBJECT 的数据,全局的,a和b。这样子这两个值就是可以被外部引用,进行修改的了。

如果我们把 add.c  中的 int a=5;改成static int a=5;那么最终链接的时候hello.o 就找不到a变量,导致链接失败。

这也就是static的作用,让只想对当前的.c能访问,做的对修饰的变量或者函数进行限定。

于是,我们常规的模式就是,对内的都用static进行修饰,然后放出对外函数,让其操作数据,保证入口的统一性,也更容易追踪。具体如下:

用静态修饰变量,不让外部直接访问,然后对外放出函数,让其通过函数修改数据,保证了入口的唯一性,这样子调试也很简单,直接在函数设置断点,打印堆栈,直接能找到调用方。

而如果说你让int a这种随意的变量放置到全局,就是一个灾难,会出现莫名奇妙被修改,找半天找不到被谁修改的问题。

说完了全局变量,全局函数前面加static,下来说下函数内部,添加static的妙用。

函数中的局部变量,默认是都在栈上面,这类变量最大的特点就是,函数返回之后,这段区域就会被其他函数调用时覆盖,重复利用,这也是栈的特点。

那么如果我们想做一个记数,用来记录这个 add 函数被调用的次数。该如何设计呢?

我们可以用一个全局静态变量来记录,比如 static int call_add_times=0;

然后在add方法里面进行记数,这样来操作。

这样子不舒服的一点就是,本该是在add内部的一个变量,被丢到全局区域,这样子就会有个问题,会被本文件的其他地方调用,但我们设计的这个变量,只想让add函数用。

于是,我们可以这样子处理:

int add()

{

    static int call_add_times=0;

    call_add_times++;

    return a+b;

}

这样子操作后,call_add_times就会从栈区域进到全局变量区域,但是又能保证只对add函数可见,其他函数都调用不到。

你说,妙哉否?

我们在学习一些语言,技巧的时候,尽量要去思考它的使用场景,这样子的话,你就知道,它的每个设计,都是为了解决一类问题,也就是需求推动设计。

好了,今天就说的这里,不知道你学的开心不开心?下一节我们来说下,关于inline 关键字的用法,这个比较简单,我们下一节见!

喜欢,帮忙转发~~

~~ end not end ~~

热门文章

零基础新手自学Python编程教程入门精通学习资料网站大全

自学编程C语言不迷路,我私藏的书单分享给你!

零基础新手学习算法Leetcode刷题指南

程序员码农IT工程师自学编程计算机入门进阶学习网站大全

程序员面试题宝典以及相关书籍下载!

计算机类常用电子书整理大全

职场老鸟,互联网十年从业生涯,分享 [Java,Python,安卓,AI,爬虫] 技术文章,学习资料, 热点趣闻等。关注回复 1024 Python 电子书大全 面试资料,给你一份私藏的程序员好礼,永远更新中!赶紧来关注哦!

我的微信 code_gg_boy 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

计算机毕业设计(源码都能跑起来)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值