static关键字
static是一个面试中被问到频率较高的关键字,今天我们一起来总结一下static的作用,要说static关键字,还要从C语言和C++俩个方面说起。
1.C语言中static关键字
1.1static可以修改标识符的链接属性
当编译多个文件时,未加static的函数和全局变量使用extern都有全局可见性,我们来举个栗子
//test.h
char a = 'A';
void fun1()
{...}
//main.c
extern char a;
fun1();
printf("%c ", a);
此时文件通过编译,因为此时我们的并未对fun1()函数和a变量进行static进行修饰,此时他们还是全局可见的,但是如果我们在test.h头文件中给他们加上static关键字修饰那么程序编译就会产生链接错误,函数和变量相当于被隐藏了,我们可以使用static的这一特性来在不同文件中定义同名的变量。
//test.h
static char a = 'A';
static void fun1()
{...}
特点
- static对函数来说仅仅只有隐藏的作用,对于以上函数和变量来说仅仅改变了他们的链接属性但是并未改变他们的存储类型。
1.2static可以改变标识符的存储类型
下面这段代码虽然调用了俩次fun1函数,但是实际上调用的效果是一样的,每一次sum都被初始化为1,加上1后赋值给x,所以x返回给a输出2
int fun1(int x)
{
int sum = 1;
sum += 1;
x = sum;
return x;
}
int main()
{
int a;
a = fun1(1);
a = fun1(1);
printf("%d", a);//输出结果为2
system("pause");
return 0;
}
但是我们给int sum前加上static
static int sum = 1;
此时结果输出3,因为我们将sum这个变量从自动变量修改成了静态变量,变量的链接属性没有发生变化,但是当第一次调用这个函数时,sum被创建,直到这个函数第一次调用结束时,sum(此时他不在时auto变量)也不会销毁,此时sum的值为2,即使第二次再次调用他时,重新的初始化不对他起到任何作用,直到整个程序的结束sum才被销毁。
特点
- static修饰局部变量时改变局部变量的生命周期,但是并不改变变量的链接属性和作用域,出了作用域他依然存在但是无法对他进行访问。
1.3static可以默认初始化为0
全局变量实际上也会存在这一属性,因为他们都存储在了静态区,内存中所有的值都默认为0x00,我们可以做以下的一个小实验
int main()
{
static char a[10];
printf("_%s_", a);
system("pause");
return 0;
}
打印结果
__
说明一个字符串static也会初始化为0.
总结:static的主要功能是隐藏,其次因为static变量存储在静态区,所以有了持久性和默认设置为0的特性
2.C++中的static
2.1static修饰类数据成员
下面对_year的初始化是错误的,因为类中static数据成员需要在类外初始化:
class date
{
public:
date(int year=1900,int month=1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
private:
static int _year;
int _month;
int _day;
};
正确的方式:
初始化方式:<数据类型><类名>::<静态数据成员名>=<值>
特点
- 静态成员存储在全局数据区,所以在定义时需要分配空间,不可以在类中定义。如果未对其初始化,编译器将他自动初始化为0,类中的静态成员会在静态区单纯开辟空间,即使不定义对象,也为静态成员开辟空间。
- 静态成员也遵循类访问限定符规则
- 因为静态数据成员并不属于类的某个对象,它属于这个类的所有对象,这个静态成员只初始化一次,并且可以被类的所有对象调用,而类对象中的非静态数据,每个对象都有自己的一份拷贝。
2.2static修饰成员函数
class date
{
public:
date(int year=1900,int month=1,int day=1)
:_month(month)
,_day(day)
{}
static int Day(){}//此处被声明为静态成员函数
public:
static int _year;
int _month;
int _day;
};
同样,静态成员函数也是属于一个类的,并不是属于某一个对象的,它为类全部服务,而不是为了对某一个对象服务,静态成员函数的存在并不是为了服务类的数据成员,而是为了处理静态数据成员。
特点:
- 出现在函数体外的定义不能指定为关键字static。
- 静态成员可以在类内互相访问,因为他们都属于本类。
- 静态成员函数不能访问非静态成员函数和非静态数据成员。
- 非静态成员函数可以任意的访问静态数据成员和静态成员函数。
- 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长。