浅谈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 ...
随机推荐
- 1.4WEB API 路由配置及参数传输
在没有添加路由时,webapi 的访问比较恶心,访问的时候是没有接口方法的.如果定义了同样参数的方法,它就傻傻的分不清的,为了解决这个问题,我们加上路由吧. 这是生成的api帮助文档列表,可以看到下面 ...
- format的应用
>>> "{a} love {b}.{c}".format(a="I", b="Fish", c="com&qu ...
- requests-文件上传
import requests files = {'file':open('D://tomas.jpg','rb')}#设定一个files,打开文件对象 response = requests.pos ...
- 使用requirejs来管理angularJS依赖示例
有关requirejs是什么在这里不做解释,只用纯代码实战让你感受requirejs依赖管理的强大. 一.首先要先下载require.js,然后整一个入口文件main.js包括了对其他js的引用. / ...
- 关于if后面直接加上参数名,不加条件的用法
<template> <section> <p v-if="aa">{{aa}}</p> <p v-if="bb&q ...
- 使用WSUS离线下载补丁并安装在非联网的windows系统中(以Windows Server 2008 r2为例)
首先我失去https://serverfault.com/questions/322938/finding-and-downloading-all-available-win2008-r2-and-w ...
- MySQL实现全关联 full outer join
SQL LEFT JOIN 关键字 LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行. LEFT JOIN 关键 ...
- 从源码看JDK提供的线程池(ThreadPoolExecutor)
一丶什么是线程池 (1)博主在听到线程池三个字的时候第一个想法就是数据库连接池,回忆一下,我们在学JavaWeb的时候怎么理解数据库连接池的,数据库创建连接和关闭连接是一个比较耗费资源的事情,对于那些 ...
- 一 Django模型层简介(一)
模型 django提供了一个强大的orm(关系映射模型)系统. 模型包含了你要在数据库中创建的字段信息及对数据表的一些操作 使用模型 定义好模型后,要告诉django使用这些模型,你要做的就是在配置文 ...
- mysql sql语句执行时是否使用索引检查方法
在日常开发中,使用到的数据表经常都会有索引,这些索引可能是开发人员/DBA建表时创建的,也可能是在使用过程中新增的.合理的使用索引,可以加快数据库查询速度.然而,在实际开发工作中,会出现有些sql语句 ...