当前位置: 首页 > 科技观察

关键字Static的使用详解

时间:2023-03-21 16:23:49 科技观察

粉丝问粉丝问题,总结一下:如何使用关键字static。Question要弄清楚关键字static的使用方法,首先要搞清楚可执行程序段的分类和每个段的逻辑地址在内存区的映射。本文配套视频请看下一篇《【视频讲解】C语言static关键词》一、可执行程序内存分配1、可执行程序段一个程序有三个基本段:文本段、数据段、bss段BSSBSS(BlockStartedbySymbol)通常指的是一块内存区域,用于存放程序中未初始化的全局变量和静态变量。特点是:可读可写,BSS段在程序执行前会自动清0。因此,未初始化的全局变量在程序执行之前已经变为0。注意与数据段的区别。BSS存放未初始化的全局变量和静态变量,数据段存放初始化的全局变量和静态变量。在UNIX下,可以使用size命令查看可执行文件的段大小信息。例如尺寸a.out。数据段.data存放的是编译阶段(而不是运行时)就可以确定的数据,是可读可写的。它也通常被称为静态存储区。赋初值的全局变量和赋初值的静态变量都存放在这个区域,常量也存在这个区域。数据段和代码段在程序运行前就已经确定了。代码段.text代码段通常指的是一块内存区域,用来存放程序执行代码。这部分区域的大小在程序运行之前就已经确定了,内存区域通常是只读的,有些架构还允许代码段是可写的,从而允许程序进行自我修改。在代码段中,也可以包含一些只读的常量变量,比如字符串常量等。文本段是在编译时确定的,在内存中被映射为只读,但是日期段和bss段是可写的。二、c语言的五大内存分区1、栈区(stackareastack)栈由编译器自动分配和释放,存放函数参数和局部变量值(auto型),操作方法类似数据结构中的堆栈。栈的申请是系统自动分配的,比如在函数内部申请一个局部变量inth,同时判断申请的空间是否小于栈的剩余空间,如果更小,为它开辟空间,为程序提供内存,否则会报栈溢出异常。2.堆(heap)堆一般是由程序员分配和释放的。如果程序员不释放它,程序可能会在程序结束时被操作系统回收。它在数据结构上不同于堆。分配方式类似于链表,应用由程序员自己使用malloc或new操作。申请过程相对复杂。当系统收到程序的申请时,会遍历记录空闲内存地址的链表,找到第一个空间大于申请空间的堆节点,然后从空闲节点链表中删除该节点,并将该节点的空间分配给程序。在某些情况下,新申请的内存块的首地址会记录本次分配的内存块的大小,以便在free()时正确释放内存空间。3.全局静态存储区全局变量和静态变量存储在一起。初始化的全局变量和静态变量存储在一个区域中,未初始化的全局变量和未初始化的静态变量存储在相邻的另一个区域中。.4、文本常量区常量字符串放在这部分,一个只读的存储区,程序结束后由系统释放。5.程序代码区存放程序的二进制代码区。两者的区别在于:代码段、数据段、堆栈段是cpu级别的概念,而五大分区属于语言级别的概念,两者是不同的概念。3、可执行程序内存空间与逻辑地址空间的映射与划分。左边是UNIX系统的执行文件,右边是进程对应的逻辑地址空间的划分。4.例子2.静态变量静态变量主要区分静态全局变量和全局变量、局部变量、静态局部变量的区别。1.静态全局变量、全局变量静态全局变量和全局变量的区别主要是生命周期和作用域来区分。A。静态全局变量和全局变量都存放在数据段.data中;b.静态局部变量定义在函数内部,生命周期为整个源程序,但作用域与自动变量相同,只能在定义变量的函数内定义。内使用。退出函数后,变量虽然还在,但是不能再用了。C。基本类型的静态局部变量在解释时如果没有赋初值,系统会自动赋值为0。但是如果自动变量没有赋初值,它的值是不确定的。d.全局变量本身就是一种静态存储方式,当然静态全局变量也是一种静态存储方式。但是它们的作用域,非静态全局变量的作用域是整个源程序(可以多个源文件一起使用);而静态全局变量限制了它们的作用域,即只在定义该变量的源文件中有效,不能在同一源程序的其他源文件中使用。全局变量示例下面是b.c和a.c源代码全局变量编译gcca.cb.c的执行结果:从编译结果可以知道执行结果,文件a.c可以访问b.c文件中的静态全局变量b。静态全局变量实例编译结果编译结果显示文件a.c无法访问文件b.c中的静态全局变量b,所以编译时报错。2.staticlocalvariables,局部变量staticlocalvariables和localvariables的区别主要是生命周期和作用域来区分。静态局部变量存放在数据段.data中,局部变量在栈上;静态局部变量和局部变量都只能在函数体内访问。函数每次访问的静态局部变量,该变量的值为上次访问修改后的值。示例:1#include234voidfunc()5{6intaa=11;78printf("aa=%d\n",aa++);910}1112intmain(intargc,char**argv)13{1415func();16func();1718return0;19}对于普通局部变量,每次调用都会在栈中初始化一次,1#include234voidfunc()5{6staticintaa=11;78printf("aa=%d\n",aa++);910}1112intmain(intargc,char**argv)13{1415func();16func();1718return0;19}函数中的静态变量aa只初始化一次,取值每次访问应该是最后一次调用这个函数的最后处理结果。三、静态函数1、概念:在函数的返回类型前加上关键字static,将函数定义为静态函数。函数的定义和声明默认是extern的,但是静态函数只在声明它的文件中可见,不能被其他文件使用。静态函数(也叫内部函数)只能被本文件中的函数调用,不能被同一程序的其他文件中的函数调用。不同于一般的非静态函数(外部函数)static在c中可以用来修饰变量,也可以用来修饰函数。先看它什么时候用于修改变量。c中的变量可以分为全局数据区、栈和堆。其实我们平时说的栈就是栈,不包括堆,大家不要搞混了。2.定义静态函数的好处:<1>可以在其他文件中定义同名函数而不会产生冲突。不用担心你定义的函数会不会和其他文件中的函数同名,因为同名并不重要。<2>静态函数不能被其他文件使用。存储说明符auto、register、extern、static分别对应两个存储周期:自动存储周期和静态存储周期。<3>计数次数函数声明一个函数的局部变量,设置为静态类型作为计数器,这样函数每次调用都可以计数。这是统计函数被调用次数的最好方法,因为这个变量与函数密切相关,函数可能在很多不同的地方被调用,所以从调用者的角度很难统计。<4>静态函数会自动分配到一个一直使用过的存储区,直到应用实例退出,避免了函数调用时的压栈和出栈,速度快很多。示例a.c1#include23voidfunc();45intmain(intargc,char**argv)6{78func();910return0;11}b.c1#include23intb=10;456staticvoidfunc()7{8printf("infuncb=%d\n",b);9}编译从编译结果可以看出,文件a无法访问文件b中的静态函数func。