static关键字在c和c++中的作用

1、c语言中static的作用

1.1、先来介绍它的第一条也是最重要的一条:隐藏

当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。
下面是a.c的内容

//静态全局变量 static char a = 'A';静态函数 static void msg(){};
char a = 'A'; // global variable
void msg() 
{
    printf("Hello\n"); 
}

下面是main.c的内容

int main(void)
{    
    extern char a;    // extern variable must be declared before use
    printf("%c ", a);
    (void)msg();
    return 0;
}

程序的运行结果是:
A Hello

你可能会问:为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。
如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。

1.2、static的第二个作用是保持变量内容的持久

存储在静态数据区的变量会在程序刚开始运行时就完成初始化也是唯一的一次初始化共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。

//静态局部变量
#include 

int fun(void){
    static int count = 10;    // 事实上此赋值语句从来没有执行过
    return count--;
}

int count = 1;

int main(void)
{    
    printf("global\t\tlocal static\n");
    for(; count <= 10; ++count)
        printf("%d\t\t%d\n", count, fun());    

    return 0;
}

程序的运行结果是:

global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1

1.3、static的第三个作用是默认初始化为0

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。不妨做个小实验验证一下。

#include 

int a;

int main(void)
{
    int i;
    static char str[10];

    printf("integer: %d;  string: (begin)%s(end)", a, str);

    return 0;
}

输出结果

integer: 0; string: (begin)(end)

可以看出全局变量和静态变量都会初始化为0,如果是字符串,都会是’\0’

总结在c语言的特点:

1、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。而且仅初始化一次,即在内存中仅有一份
2、隐藏作用:变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别,如静态全局变量对其它文件不可见;静态局部变量对其它函数不可见
3、全局变量和静态变量如果没有手动初始化,则由编译器初始化为0

设计总结:
1、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度
2、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度

2、C++中的static

C++的static有两种用法:面向过程程序设计的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。

2.1、面向过程设计中的static 和在c语言中相同

举其中一个静态局部变量的例子


#include <iostream.h>
void fn();
void main()
{
	 fn();
	 fn();
	 fn();
}
void fn()
{
	 static n=10;
	 cout<<n<<endl;
	 n++;
}

程序输出结果:
10
11
12
通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。但是有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。  静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下次函数的调用

2.2 面向对象程序设计中

在类中,static可以用来修饰静态数据成员和静态成员方法

2.2.1 在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员
  • 无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员
  • 静态数据成员初始化的格式为:
    <数据类型><类名>::<静态数据成员名>=<值>
2.2.2 静态数据成员的两种访问形式:

<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

2.2.3 同全局变量相比,使用静态数据成员有两个优势
  • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  • 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能
//Example5
#include <iostream>
using namespace std;
class Myclass
{
    public:
        Myclass(int a, int b, int c);
        void GetSum();
    private:
        int a;
                int b;
                int c;
        static int Sum;//声明静态数据成员
};
int Myclass::Sum = 0;//定义并初始化静态数据成员
 
Myclass::Myclass(int a,int b,int c)
{
    this->a = a;
    this->b = b;
    this->c = c;
    Sum += a + b + c;
}
void Myclass::GetSum()
{
    cout<<"Sum="<<Sum<<endl;
}
int main()
{
    Myclass M(1, 2, 3);
    M.GetSum();
    Myclass N(4, 5, 6);
    N.GetSum();
    M.GetSum();
}
2.2.4 静态函数成员

普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指 针从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数

//Example 6
#include <iostream>
using namespace std;
class Myclass
{
    public : 
        Myclass(int a, int b, int c);
        static void GetSum(); // 声明静态成员函数
    private : 
        int a, b, c;
        static int Sum; //声明静态数据成员
};
int Myclass::Sum=0; //定义并初始化静态数据成员
Myclass::Myclass(int a, int b, int c)
{
    this->a = a;
    this->b = b;
    this->c = c;
    Sum += a + b + c; //非静态成员函数可以访问静态数据成员
}
void Myclass::GetSum() //静态成员函数的实现
{
    // cout<<a<<endl; //错误代码,a是非静态数据成员
    cout<<"Sum="<<Sum<<endl;
}
int main()
{
    Myclass M(1, 2, 3);
    M.GetSum();
    Myclass N(4, 5, 6);
    N.GetSum();
    Myclass::GetSum();
}

参考:
https://blog.csdn.net/jinzhichaoshuiping/article/details/50485320?utm_source=blogxgwz9&tdsourcetag=s_pctim_aiomsg
https://baike.baidu.com/item/static/9598919

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值