参考:博文1:https://www.cnblogs.com/love-yh/p/7507630.html
博文2:https://blog.youkuaiyun.com/guotianqing/article/details/79828100
博文3:https://blog.youkuaiyun.com/junboyboy/article/details/17921763
文章目录
一、研究对象和问题
static全局变量、static局部变量、static函数
问题一:static全局变量与普通的全局变量有什么区别?
问题二:static局部变量和普通局部变量有什么区别?
问题三: static函数与普通函数有什么区别?
二、要回答这几个问题之前需要先学习static关键字的用法,这才是解答问题,学会技能的正确方式:
c++语言中static关键字用法详解 (来源:博文2)
概述
static关键字在c语言中比较常用,使用恰当能够大大提高程序的模块化特性,有利于扩展和维护。
但是对于c语言初学者,static由于使用灵活,并不容易掌握。本文就static在c语言中的应用进行总结,供参考使用。错漏之处,请不吝指正。
在程序中使用static
变量
1. 局部变量
(1)普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。
普通局部变量存储于进程栈空间,使用完毕会立即释放。
(2)静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
静态局部变量总结来说:
1) 静态局部变量在全局数据区分配内存空间;
2)声明静态局部变量未赋初值时,编译器自动对其初始化为0
3)作用域:其作用域为局部作用域,只在 定义它的函数中有用
4)生命周期:当定义它的函数结束时,其作用域随之结束,但是它的值会保存下来,下次调用时静态变量的初始化语句就不再起作用。 生命周期一直持续到程序运行结束。
小程序体会一下静态局部变量的威力:
#include <stdio.h>
void fn(void)
{
int n = 10;
printf("n=%d\n", n);
n++;
printf("n++=%d\n", n);
}
void fn_static(void)
{
static int n = 10; //但是它的值会保存下来,下次调用时静态变量的初始化语句就不再起作用。
printf("static n=%d\n", n);
n++;
printf("n++=%d\n", n);
}
int main(void)
{
fn();
printf("--------------------\n");
fn_static();
printf("--------------------\n");
fn();
printf("--------------------\n");
fn_static();
return 0;
}
运行结果如下:
-> % ./a.out
n=10
n++=11
--------------------
static n=10
n++=11
--------------------
n=10
n++=11
--------------------
static n=11
n++=12
可见,静态局部变量的效果跟全局变量有一拼,但是位于函数体内部,就极有利于程序的模块化了。
2. 全局变量
全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。
1、普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
2、静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
3.函数
函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。
1、静态函数
(1)定义:在函数的返回类型前加上关键字static,函数就被定义成为静态函数。
(2)static函数(静态函数)其特性如下:
1)静态函数只能在声明它的文件中可见,其他文件不能引用该函数
2)不同的文件可以使用相同名字的静态函数,互不影响
(3)定义静态函数的好处:
1) 其他文件中可以定义相同名字的函数,不会发生冲突
2) 静态函数不能被其他文件所用。
扩展阅读:
存储说明符auto,register,extern,static,对应两种存储期:自动存储期和静态存储期。
auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。
关键字extern和static用来说明具有静态存储期的变量和函数。用static声明的局部变量具有静态存储持续期(static storage duration),或静态范围(static extent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。
由于static变量的以上特性,可实现一些特定功能。见文末博文2总结。
2、普通函数
(1)非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明
因为函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。
下面两个文件的例子说明使用static声明的函数不能被另一个文件引用:
/* file1.c */
#include <stdio.h>
static void fun(void)
{
printf(“hello from fun.\n”);
}
int main(void)
{
fun();
fun1();
return 0;
}
/* file2.c */
#include <stdio.h>
static void fun1(void)
{
printf("hello from static fun1.\n");
}
使用 gcc file1.c file2.c编译时,错误报告如下:
/tmp/cc2VMzGR.o:在函数‘main’中:
static_fun.c:(.text+0x20):对‘fun1’未定义的引用
collect2: error: ld returned 1 exit status
修改文件,不使用static修饰符,可在另一文件中引用该函数:
/* file1.c */
#include <stdio.h>
void fun(void)
{
printf("hello from fun.\n");
}
/* file2.c */
int main(void)
{
fun();
return 0;
}
同样使用 gcc file1.c file2.c编译,编译通过,运行结果如下:
-> % ./a.out
hello from fun.
4.面向对象
(1)静态数据成员 ,即static修饰类的成员变量
在类内数据成员的声明前加上static关键字,该数据成员就是类内的静态数据成员。其特点如下:
静态数据成员存储在全局数据区,静态数据成员在定义时分配存储空间,所以不能在类声明中定义
静态数据成员是类的成员,无论定义了多少个类的对象,静态数据成员的拷贝只有一个,且对该类的所有对象可见。也就是说任一对象都可以对静态数据成员进行操作。而对于非静态数据成员,每个对象都有自己的一份拷贝。
由于上面的原因,静态数据成员不属于任何对象,在没有类的实例时其作用域就可见,在没有任何对象时,就可以进行操作
和普通数据成员一样,静态数据成员也遵从public, protected, private访问规则
静态数据成员的初始化格式:<数据类型><类名>::<静态数据成员名>=<值>
类的静态数据成员有两种访问方式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
同全局变量相比,使用静态数据成员有两个优势:
静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能
(2)静态成员函数 ,即 static修饰类的成员函数
与静态数据成员类似,静态成员函数属于整个类,而不是某一个对象,其特性如下:
静态成员函数没有this指针,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数
出现在类体外的函数定义不能指定关键字static
非静态成员函数可以任意地访问静态成员函数和静态数据成员
5.总结
static是一个很有用的关键字,使用得当可以使程序锦上添花。当然,有的公司编码规范明确规定只用于本文件的函数要全部使用static关键字声明,这是一个良好的编码风格。
无论如何,要在实际编码时注意自己的编码习惯,尽量体现出语言本身的优雅和编码者的编码素质。
博文2:总结
https://blog.youkuaiyun.com/junboyboy/article/details/17921763
由于static变量的以上特性,可实现一些特定功能。
1. 统计次数功能
声明函数的一个局部变量,并设为static类型,作为一个计数器,这样函数每次被调用的时候就可以进行计数。这是统计函数被调用次数的最好的办法,因为这个变量是和函数息息相关的,而函数可能在多个不同的地方被调用,所以从调用者的角度来统计比较困难。
2、 C语言中使用静态函数的好处:
静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。
关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
c语言中static的语义1.static变量:1).局部a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。2).全局全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。2.static函数(也叫内部函数)只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数) static在c里面可以用来修饰变量,也可以用来修饰函数。 先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含对,不要弄混。
二、回答问题
问题一:static全局变量与普通的全局变量有什么区别?
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。
(1)全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。
这两者在存储方式上并无不同。
(2)作用域不同:a.这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个原文件组成时,非静态的全局变量在各个源文件中都是有效的。 b.而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。
由于静态全局变量的作用域限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。
(3) static全局变量与普通的全局变量的区别是 static全局变量只初始化一次,防止在其他文件单元被引用。
问题二:static局部变量和普通局部变量有什么区别?
static局部变量只被初始化一次,下一次依据上一次结果值;
问题三: static函数与普通函数有什么区别?
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
static函数与普通的函数作用域不同。尽在本文件中。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件。
static函数与普通函数最主要区别是static函数在内存中只有一份,普通静态函数在每个被调用中维持一份拷贝程序的局部变量存在于(堆栈)中,全局变量存在于(静态区)中,动态申请数据存在于(堆)