浅谈static其一之不死变量
在学习汇编的过程中,小有所悟,遂把自己所思所想记下,以便日后查阅。
首先说说我对这个关键字的理解。static字面上就是静止的、静态的、不变的之类的意思,所以在被它修饰之后,应该也会带有这样的一些特点。事实证明也确实是这样,利用这样的特点能很方便的达到一些编程实践中所要达到的一些效果。而它的存在在本质上又有什么样的原理在里面呢?说到这,我就不得不说,学底层的东西有一点好,就是能了解原理。对于我这样的一个喜欢知根知底的人来说,确实很有吸引力。
存储角度:
在最近的汇编学习中,我了解到内存中有(但不是仅有)3中不同的区域,分别是:静态存储区域、堆和栈。然后它们有着不同的职能,而静态存储区就和我们这次要聊的static有着莫大的关联。
大家都知道,程序要先加载到内存中,才能正常工作。那有没有具体想过,程序究竟是怎么被加载到内存中的?以及,程序到底是啥?就我现在的理解,程序在存储的角度看,就是变量和函数。所以,把程序加载到内存也就是把变量和函数加载到内存。那么问题就来了,这里的变量是哪些变量呢?好吧。。其实哪种变量都有可能,我最关注的就是全局变量和静态变量(被static修饰的变量)。
因为这两种变量是要被放到内存的静态存储区的(对,变量虽然都是变量,但存储的位置却大有不同)。所以说,从存储的角度看,全局变量和静态变量是存储在同一地方的,而且这两种变量(所占的空间)还是要写死在生成的目标可执行文件中的(对于编译型语言)。
我推断:
1.全局变量好理解,它要先于任何函数而存在,所以它不可能在栈中;而堆变量也要从函数中申请,所以在没有函数存在的前提下,存放在静态存储区的全局变量只能由目标可执行文件提供。
2.静态变量则是在函数执行完毕从栈中弹出后依然存在的,所以它肯定不在栈上,而它又不是动态申请来的,所以也不在堆上,那从存储角度讲,它的存在其实和函数是没有关系的。所以要加载它只能从目标可执行文件中来。
所以,从存储的视角来看,static变量与全局变量并无差别。
逻辑角度:
这里有两个概念要说明一下,就是作用域和生存期。
一个变量的作用域就是能访问这个变量的范围;而一个变量的生存期则是我能访问这个变量的时期或者说时机。
这样就有了至少四种组合:1.全局可访问+局部(函数内)生存期 2.全局可访问+全局生存期 3.局部可访问+局部生存期 4.局部可访问+全局生存期
第1种可能性简直是一个逆天的存在。。。单线程的程序同一时间不可能跑两个函数,所以这样的做法毫无意义。所以这种可能性根本不存在。
第2种可能性就是全局变量。
第3种可能性就是栈变量,也就是函数的局部变量。
而第4种可能性就是我们今天的重头戏,被static修饰的静态变量。(其实我暗想,堆变量也能在十分别扭的操作下达到这种效果,但是实在不是常规途径)
全局生存期对全局变量来说理所当然,但是对一个作用域是局部的函数内部的变量来说意味着什么呢?这意味着函数结束从栈中被弹出后,变量的值还存在。
这就是static的语义所在——不变的,这里的不变指的是变量的生存状态不变。哈哈,中二一点其实也可以叫它作“不死变量”。
那也许有人会问:这有什么用呢?当然有用,我最感兴趣的一个作用是:函数可以存住东西了。函数终于不再那么的“动态”了,开始有点“静态”的影子了。
举个例子的话,比如我要从一个字符串中往外一个一个地取字符,运用了static修饰符,我就可以优雅地每调用一次一个函数就取到一个直达取完。C语言的话我可以写成下边的样子。
#include <stdio.h> char getChar(char *str){
static int index = ;
char result = str[index];
index++; return result;
} int main(int argc, char const *argv[]){
char *str = "Hello World!"; char c;
while( (c=getChar(str)) != '\0' ){
putchar(c);
} return ;
}
这样的一个好处是我可以不用破坏原字符串而且是很方便地用一个独立的函数,实现了所想即所得。
全局生存期是它们的共同点,而不同则在于作用域的不同,这也是static的作用所在。全局变量,在所有函数中均可访问,那这样就会产生安全性问题,导致在用这个变量的时候不能确保它的值只被本函数所控制。这就是所谓的封装性差。而static修饰符恰能解决这一点,由于被它修饰的变量是函数的局部变量,导致它的作用域仅在这个函数内,这样我们便可安心大胆的断定,这个变量的值只由本函数控制。
而在像Java这样的语言中,却不允许用static修饰局部作用域的变量。我想可能是因为已经能有其它的方式来表达类似的语义了,虽然不完全一样。而且到了面向对象编程的时候,我们完全可以换另一种思维来考虑问题,所以也不是那么的需要这样的函数设计方式了。在Java中,static的含义与C语言中大不相同。我们目前只说了“不死变量”这一种语义,就这一点Java是没有的,可它却有另外的含义。
未完待续...
浅谈static其一之不死变量的更多相关文章
- 浅谈JS中 var let const 变量声明
浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...
- 浅谈static关键字的四种用法
1.修饰成员变量 在一个person类中,一个成员变量例如 String name,当new2个person()对象时候,这2个对象在堆的位置是不同的,给name赋值张三.李四,这两个对象的name是 ...
- 浅谈Static
A: 使用场景 static可以修饰成员变量和成员方法. 什么时候使用static修饰成员变量? 加static修饰成员的时候,这个成员会被类的所有对象所共享.一般我们把共性数据定义为静态的变量 什么 ...
- 浅谈Static关键字
1.使用static关键字声明的属性为全局属性 未使用static关键字指定city之前,如果需要将Tom,Jack,Mary三人的城市均改成Beijing,需要再次声明三次对象的city为Beiji ...
- 浅谈STM32L071硬件I2C挂死
STM32的IIC问题一直存在,在网上也被很多人吐槽,然而FAE告诉我,硬件IIC的问题在F1,F3,F4系列单片机存在,而在L0上已经解决了,然而这几天调试加密芯片和显示芯片,都是IIC芯片,却再一 ...
- 转载 浅谈C/C++中的static和extern关键字
浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...
- 【原创】浅谈指针(十二)关于static(上)
0.前言 这个系列基本上是一月一更到两月一更 今天写一篇关于static的,内含大量干货,做好准备 1.基础知识的回顾 1.1.内存的种类 一般来说,我们之前已经讲过的变量(或者说是内存)可以大体分为 ...
- 浅谈 PHP 变量可用字符
原文:浅谈 PHP 变量可用字符 先来说说php变量的命名规则,百度下一抓一大把:(1) PHP的变量名区分大小写;(2) 变量名必须以美元符号$开始;(3) 变量名开头可以以下划线开始;(4) 变量 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
随机推荐
- Hadoop:读取hdfs上zip压缩包并解压到hdfs的实现代码
背景: 目前工作中遇到一大批的数据,如果不压缩直接上传到ftp上就会遇到ftp空间资源不足问题,没办法只能压缩后上传,上穿完成后在linux上下载.但是linux客户端的资源只有20G左右一个压缩包解 ...
- Visual Studio的一些快捷键
1)CTRL + W选择当前单词 2) Ctrl+F10: 运行到光标处 1.CTRL + SHIFT + B生成解决方案 2.CTRL + F7 生成编译 3. CTRL + O 打开文件 ...
- SQL 语句 (二) --- SELECT
1 完整句法: SELECT [ ALL | DISTINCT TOP n [] WITH TIES select_list [INTO [new_table_name] ] [FROM {table ...
- 玩一玩基于Token的 自定义身份认证+权限管理
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录.大概的流程是这样的: 客户端使用用户名跟密码请求登录 服务端收到请求,去验证用户名与密码 验证成功后,服务端会签发一个 Toke ...
- 数据结构与算法 —— 链表linked list(04)
我们在上篇文章里面提到了链表的翻转,给定一个链表,对每两个相邻的节点作交换,并返回头节点,今天的这道题是它的升级版,如下: k个一组翻转链表 给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链 ...
- python打造一个Mysql数字类型注入脚本(1)
前言: 总是想写一个sql注入脚本,但是之前的那些都不行. 这次做好了准备,然后嘿嘿嘿. 准备: sql注入的基础知识 熟悉怎么判断 正文: 思路概念图: 这里我没有限制用户输入,不限制的话可能会 @ ...
- Redis常用命令--SortedSet
SortedSet是一个类似于Set的集合数据类型,里面的每个字符串元素都关联到一个score(整数或浮点数),并且总是通过score来进行排序着. 并且可以取得一定范围内的元素. 在Redis中大概 ...
- [ZJOI 2010]base 基站选址
Description 题库链接 给出 \(n\) 个村庄的横坐标 \(D_i\) .要求在这 \(n\) 个村庄内最多选择 \(m\) 个作为通讯基站,在村庄 \(i\) 建造通讯基站的代价为 \( ...
- bzoj 2229: [Zjoi2011]最小割
Description 小白在图论课上学到了一个新的概念--最小割,下课后小白在笔记本上写下了如下这段话: "对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同 ...
- bzoj3963[WF2011]MachineWorks cdq分治+斜率优化dp
3963: [WF2011]MachineWorks Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 270 Solved: 80[Submit][S ...