关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题
在进入正题前我们必须了解一些概念:
标识符:标识符不仅仅代表着变量的名字,main()函数的main也是一个标识符,这点很重要。
存储类型:即变量的存储位置及其生存周期:
静态区:分为两块
.date 已显式初始化的全局变量了静态变量
.bss 存放未初始化的全局或者静态变量
注意:
静态变量的初值是在编译时就进行初始化了;
意思就是用static修饰的变量赋过数值的话就保存为他的初值,如果没有初始化的话就赋值为零,且整个程序只初始化一次;
即不管static int i = 1;或者这 static int a 在程序中的什么位置;分别由编译器初值装入1和0保存在静态区
注意初始化只执行一次;看如下例子:
#include <stdio.h>
void add()
{
static a;
static b = 1;
printf("%d\t",a++);
printf("%d\n",b++);
}
int main()
{
int i = 0;
for(;i<5 ;i++)
{
add();
}
return 0;
}
的结果为:
0 1
1 2
2 3
3 4
4 5
堆栈区:
栈:系统自动分配和释放:例如局部变量函数或者代码块结束时释放因为就是局部变量存储在栈区。
堆:开发者自己生申请和释放(例如调用void *malloc())。它的生存周期是开发者决定的。
当你使用malloc的是后被造出来,free后被销毁。
常量区:存储常量数据;编译完成后到程序结束都存在,可以访问但是不能被修改。
链接属性:
假设我们有很多.c文件一起生成一个可执行文件例如:
test0.c test1.c test2.c
| | |
| | |
| | |
test0.o test1.o test2.o
| | |
——————————————链接
|
test
链接的作用就是将各个二进制代码文件链接生成一个可执行文件所以不管是我们写了多少个c文件最后都是要被合成一个的,
这个时候我们就该考虑一个问题各个文件的标识符是否公用,因此便引出了链接属性。
c规定链接属性分为三种:
external(全局的):各个文件访问的是同一个标识符。
internal(局部的):标识符只被该文件中定义后的地方能访问。
none(无链接属性):没有链接属性。
作用域:即标识符能被访问的代码区域大小。
代码块作用域:在代码块中定义的标识符只在定义的开始和代码块的时候能被访问,即使是被声明为静态不能使作用域扩大,这个下面会提到。
文件作用域:一般指全局变量和函数,即在整个文件中从定义的起始的位置后都能被访问。
原型作用域:即形参的作用域,一般就是在整个函数代码块中有效,它的存在是防止我们多次在函数内定义一个和形参标识符的名字冲突的标识符
因为这样我们会失去形参的值。
函数作用域:这个是用来说代码标号的作用区域的,所以他和goto有关,呵呵,我看了一眼就忘了。
下面来看几个关键字()
auto:进入程序时在栈创建,程序结束自动释放。一般局部变量自带auto属性。所以用的很少。
static:
1:用于修饰局部变量时修改的是其存储类型,使其成为静态存储。至于局部变量静态存储后的变量有什么改变参照上文的解释和例子。但是作用域不改变。
2:修饰全局标识符时,意思是将全局变量的external属性修改为internal。但是作用域不改变。
3:修饰函数时是修改它的链接属性external属性修改为internal。但是作用域不改变;
extern:
1.修饰变量时声明这个变量定义在别的文件中或者本文件其他位置的external属性的变量,一般用来修饰全局标识符(变量函数);
注意:
如果我们在标识符声明时,一旦是在函数块外部声明,那么编译器默认加多上一个external属性,而不是extern修饰符。这很重要容易混淆。
而在代码块中声明的局部变量则会被带上一个intenral的链接属性。但这不代表他只能在代码块的属性是intenral的链接属性赋予的。
真正的原因是因为局部变量被看作一个auto类型的变量。
register:即存储在寄存器中的变量,寄存器有什么特点大家都知道寄存器的取数效率很高常用于重复的变量运算。注意
不能用全局变量去申请,一般默认为auto,这和全局变量的生命周期有关。
总结:千万不能把extern和external与static与internal混淆。他们的具体解释看上文。
狗日的公司笔试其和考试题经常拿这个来考人。就像下面这个:
#include "stdio.h"
int a=1;
int f(int c)
{
static int a=2;
c=c+1;
return (a++)+c;
}
main()
{
int i,k=0;
for(i=0;i<2;i++)
{
int a=3;
k+=f(a);
}
k+=a;
printf("%d\n",k);
}
我们只要根据上文提到的知识:把变量表示符一换,就可以了:
#include "stdio.h"
int a=1;
int f(int c)
{
static int b=2;
c=c+1;
return (b++)+c;
}
main()
{
int i,k=0;
for(i=0;i<2;i++)
{
int d=3;
k+=f(d);
}
k+=a;
printf("%d\n",k);
}
问题及解决,妈妈再也不用担心我的学习。
关于extern和static关键字引出的一些关于作用域和链接属性和存储类型的问题的更多相关文章
- C和C指针小记(六)-基本声明、指针声明、typedef 、常量、作用域、链接属性、存储类型、static
1.变量的声明 声明变量的基本形式: 说明符号(一个或者多个) 声明表达式列表 说明符 (specifier) 包含一些关键字,用于描述被声明的标识符的基本类型,它也可用户改变标识符的缺省存储类型和作 ...
- C++中extern “C”含义及extern、static关键字浅析
https://blog.csdn.net/bzhxuexi/article/details/31782445 1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C ...
- [C]控制外部变量访问权限的extern和static关键字
一.extern 概述 编译器是由上至下编译源文件的,当遇到一些函数引用外部全局变量,而这个变量被定义在该函数声明主体的下方,又或者引用自其它的编译单元,这个情况就需要extern来向编译器表明此变量 ...
- C语言的存储类型和关键字extern、static
1.C语言中每个变量都有3个性质:存储期限.作用域.链接 1)存储期限:变量的存储期限决定了为变量预留的内存被释放的时间.共2种,自动存储期限(auto),静态存储期限(static),自动存储(au ...
- extern、static、auto、register 定义变量的不同用法
首先得说明什么叫“编译单元”.每个 .c 文件会被编译为一个 .o 文件,这个就是一个编译单元.最后所有的编译单元被链接起来,就是一个库或一个程序. 一个变量/函数,只要是在全局声明的,链接之后都隐含 ...
- 链接(extern、static关键词\头文件\静态库\共享库)
原文链接:http://www.orlion.ga/781/ 一. 多目标文件的链接 假设有两个文件:stack.c: /* stack.c */ char stack[512]; int top = ...
- C语言中的static关键字
C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错.伴随着不同源文件变量和函数之间的相互 ...
- static关键字 详解
原文地址:http://blog.csdn.net/keyeagle/article/details/6708077 google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇 ...
- C/C++ static 关键字
在 C/C++ 中,static 关键字使用恰当能够大大提高程序的模块化特性. static 在 C++ 类之中和在类之外的作用不一样,在C语言中的作用和在 C++ 类之外的作用相同,下面一一说明: ...
随机推荐
- Studio for Winforms FlexGrid: 创建分类汇总
C1FlexGrid.Subtotal方法可以增加包含普通(非小计)行的汇总数据的分类汇总行. 分类汇总支持分层聚合.例如,如果你的表格包含销售数据,你可能会通过产品.地区和推销员来小计一下以得出总的 ...
- FreeBSD的新一代包管理工具Pkg 1.3.0 发布
Pkg 是 FreeBSD 下一代的打包管理工具,用来替代原来的 pkg_info/pkg_create/pkg_add 工具,可以本地打包,也提供远程打包,主要是为了方便远程二进制包升级. Pkg ...
- java之Class类详解
测试中需要用到的代码 InterfaceA代码: package jichu; interface InterfaceA { String s1 = "this is s1 in Inter ...
- 不变(Invariant), 协变(Covarinat), 逆变(Contravariant) : 一个程序猿进化的故事
阿袁工作的第1天: 不变(Invariant), 协变(Covarinat), 逆变(Contravariant)的初次约 阿袁,早!开始工作吧. 阿袁在笔记上写下今天工作清单: 实现一个scala类 ...
- dubbo序列化的一点注意
最近工作中遇见了一个小问题,在此记录一下,大致是这样的,有一父类,有一个属性traceId,主要是记录日志号,这样可以把所有日志串起来,利于排查问题,所有的pojo对象继承于此,但是其中一同事在子类p ...
- 【使用 DOM】使用 Window 对象
1. 获取 Window 对象 可以用两种方式获得Window对象.正规的HTML5方式是在Document对象上使用defaultView属性.另一种是使用所有浏览器都支持的全局变量window . ...
- 通过FTP连接Azure上的网站
下载发布文件 使用记事本(或其他文本工具)打开 找到ftp连接地址以及用户名.密码 使用ftp工具进行连接 输入相应参数,连接即可
- 在Android Studio中用Gradle添加Robolectric
我们用Robolectric测试的话需要在gradle中进行配置,国内的详细教程太过简易,而且很多是低版本下的配置方案.所以经过本人的仔细摸索,找到了现在高版本中的配置方案,主要还是参考了官网的配置教 ...
- java 之 对象与垃圾回收
1.垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(如数据库连接,网络IO等资源) 2.程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候运行.当对象永久的失去引用后,系统会在合适的时 ...
- 【SVN】Unable to connect to a repository at URL 'svn://localhost/Test'
早上配置SVN,但是这次不是那么顺利... 环境: Windows 7 SVN服务器端:CollabNetSubversion-server-1.8.13-1 SVN客户端:TortoiseSVN_V ...