科锐课堂笔记:2017/3/9 静态变量

  extern关键字声明一个外部变量,告诉编译器该变量在别的文件里(其他OBJ中应该有此变量的符号导出)。


  static关键字声明一个静态变量,只要是静态的其符号都不会在OBJ中被导出,无论全局静态变量、局部静态变量或者是静态函数。OBJ符号不导出于是在编译链接文件的时候,其他OBJ就无论访问到这些变量或函数。所以凡是静态的作用域都不能跨文件,在C语言时代static关键字有表示私有的意思,类比C++类中private那种意味。反之可知,非静态函数和全局变量的符号都会被导出,所以在不同文件里都可以引用(事先要声明一下)。


  再说局部静态变量的作用域问题,比如有一个test函数中声明了一个局部静态变量abc,编译器对变量名(全局、静态局部)使用名称粉碎的机制,比如VC6编译器(.c文件)会把test函数内变量abc的名称改成_?abc@?1??test@@9@9这样的名字,里面包含很多信息有变量的名字,在哪个函数里第几个块,变量类型等。如果函数外部也有一个叫abc的全局变量,它的名字是_abc,这样一来源码中我们看到的变量名是一样的,而其实编译器用它自己的规则对名字作了处理,是两个不同的名字,当在test内部引用abc变量时,编译器会先把abc转成abc_?abc@?1??test@@9@找到并引用,如果在另一个函数里引用abc是肯定找不到其符号的(转换后的有函数名,不匹配),于是接着再查找_abc等于是引用了全局变量。名称粉碎机制以此区分和限制作用域。


  最后是静态局部变量的初始化问题,首先在内存中静态局部变量是和全局变量放在一块的,按照语法规定静态局部变量只初始化一次,以后重入该函数,函数内的静态局部变量都不会被初始化,初始化的值无非两种,常量或变量。首先如果初始化为常量,没什么好说的,因为静态局部变量除了编译器使用名字粉碎机制限制了其作用域,其他形为可以看作等同于全局变量,初始常量化其常量值直接保存在它的内存位置。(程序执行前就在了)
  这里主要谈一谈静态局部变量初始化为一个变量,(纯C不支持,C++支持)。比如一个静态局部变量X初始化为一个全局变量Y的值。按照语法的理解,只有当第一次进入函数的时候,X才会也仅有一次被初始化,其初始值等于此时Y的值。这是理论上的,但是编译是实际上是怎么实现的?例如有这样一个函数:
 
  进去看一下反汇编是怎么实现的:
 
  看高亮部分,429C78是静态局部变量ak47的地址,后面二句很好理解取全局变量m4的值并赋值给ak47,再往上看有个非0跳转,跳转到401061正好是m4赋值完ak47之后,连起来看先判断了一个条件,根据条件情况确定是否将m4赋值给ak47,还记得语法是怎么规定的?静态局部只初始一次。那么可知429C7C位0存放着ak47是否已经初始化的状态,0表示未初始,1表示初始化,再观察一下地址429C7C不就紧连ak47地址之后吗,这下明白了,原来VC6编译器通过分配另外的字节存放记录静态局部变量是否已经初始化,且1位对应1个静态局部,地址是相连的。知道了这样的内存结构,完全可以改写状态位使静态局部变量进行多次初始化,比如在ak47++后加上一条((int*)&ak47)[1] &= 0xFFFFFFFE,每次调用test输出的都将是999。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值