static关键字详解(C/C++)

简介: static关键字详解(C/C++)

前言

static关键字在C/C++/JAVA编程语言中都存在,而且在编程中经常会遇到,那么,在C/C++中,static究竟意味着什么?那么static修饰的变量和函数有什么样的特点呢?

本篇内容提要:

可以说,所有的静态变量都有几个共同特点:

  1. 在main函数执行之前就分配了内存(分配在全局数据区),整个程序执行完才会被销毁;
  2. 若没有初始化,会被程序自动初始化为0

1.静态局部变量

一般的局部变量有一个问题,就是生命周期短,所以我们经常会定义全局变量,但是在实际的开发中,若全局变量定义太多,很容易出现重名的问题,而且也不容易区分,所以在一般的开发中,并不会定义过多的全局变量。

静态局部变量同时具备局部变量的防重复和生命周期长两个优点,可以很好地解决这个问题。

比方说:

#include <iostream>
void print_fun()
{
  static int a = 0;
  a++;
  printf("a = %d\t", a);
}
int main()
{
  int add = 0;
  while (add < 10)
  {
    print_fun();
    add++;
  }
  printf("\n");
}

打印输出:

从以上这个简单的例子,就可以说明问题。

2.静态全局变量

与局部静态变量类似,只不过静态全局变量虽然也是全部变量,但是仅限在本文件中使用。例如;

mian.cpp文件中程序如下:

#include <iostream>
extern short ex;
int main()
{
  printf("%d\n", ex);
}

而在example.c文件中,程序如下:

#include <iostream>
static short ex = 0;

运行,出现如下问题:

可以看出,被static修饰的全局变量,仅仅作用在本文件中,其他文件中无法使用。

3.静态函数

静态函数相对来说比较简单,同样是对外不可见的。例如;

mian.cpp文件中编写程序如下:

#include <iostream>
#include "example.h"
int main()
{
  static_print_ex();
}

example.h中编写程序如下:

#pragma once
extern short ex;
static void static_print_ex();

example.cpp中编写程序如下:

#include <iostream>
#include "example.h"
static void static_print_ex()
{
  printf("The static external function is called!");
}

执行后,出现如下错误:

而在该函数的声明和定义中去掉static后,再次执行,打印输出如下:

可以看到,程序可以正常执行,也就是静态函数的应用场景就是:

部分函数只想在本文件中使用,为了避免在其他文件中被使用,就可以采用这样的方法。

这个很好解释,就好比const关键字一样,即使我们知道变量定义的时候知道是常量,不想再二次赋值,但是在后续的开发中,为了防止该变量的值被修改,还是会加上const关键字。

4.静态成员变量

因为静态数据成员在全局数据区分配内存,由本类的所有对象共享,所以,它不属于特定的类对象,不占用对象的内存,而是在所有对象之外分配内存,在没有产生类对象时其作用域就可见。因此,在没有类的实例存在时,静态成员变量就已经存在,我们就可以操作它。例如:

假设有个用户类Userm_Usersum是当前系统中某产品的用户数量,所以在任何实例中,查询用户数量都是一样的,然而当某地的用户数量增加的时候,整个产品总的用户数量也会随之增加。

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  User *User1;
  printf("There are %d users!\n", User1->GetUsersum());
  User1->SetUsersum(101);
  User *User2;
  printf("There are %d users!\n", User2->GetUsersum());
  User2->SetUsersum(102);
  printf("There are %d users!\n", User1->GetUsersum());
  printf("There are %d users!\n", User2->GetUsersum());
}

打印输出:

可以看到,静态成员变量对每个类都是一样的,共享的,因为无论有多少个类,静态成员变量在内存中只有一份,所以无论在哪个实例中修改变量的值,在其他类中获取到的值都是一样的。

然后验证一下在类实例化之前访问静态成员变量。

编写代码如下:

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  printf("There are %d users!\n", User::m_Usersum);
}

打印输出:

可以看到,在类没有实例化的时候,静态成员变量已经初始化成功,我们可以随时访问。

5.静态成员函数

1.与普通函数相比,静态成员函数属于类本身,而不作用于对象,因此它不具有this指针。

这句话如何理解呢?

静态成员函数确实属于类,但是和类的对象关系不大,不会牵扯到类的构造析构当中来,所以也不会有this指针。

关于this指针,网上有这样一段描述:

首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员函数如何知道哪个对象的数据成员要被操作呢,原因在于每个对象都拥有一个指针:this指针,通过this指针来访问自己的地址。

2.静态成员函数不能访问非静态成员函数和非静态成员变量

这时候为什么呢?

还是和创建时间有关系,静态成员函数在类的实例化之前就已经存在了,这个时候类还没来得及实例化,根本无法访问非静态成员函数和非静态成员变量。

可以验证一下在类实例化之前访问静态成员函数。

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  printf("There are %d users!\n", User::GetUsersum());
}

打印输出:

可以看到,程序可以正常运行。

参考文献

知乎:C/C++ 中的static关键字

哔哩哔哩:C语言关键字static使用及其注意事项

----------------------------------------------------------------------------------END----------------------------------------------------------------------------------

相关文章
|
18天前
|
C++
C/C++静态链接pthread库的坑【-static -pthread】
C/C++静态链接pthread库的坑【-static -pthread】
|
2月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
3月前
|
存储 安全 编译器
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
53 5
|
2月前
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
|
3月前
|
存储 编译器 程序员
C++一分钟之-auto关键字与类型推导
【6月更文挑战第21天】`auto`在C++11中重生,简化了类型声明,尤其在处理复杂类型时。它让编译器根据初始化值推导变量类型,减少了冗余和错误。使用`auto`简化了迭代器声明和函数返回类型推导,但也带来挑战:类型推导可能不直观,未初始化的`auto`是错误的,且过度使用影响可读性。使用`auto&`和`auto*`明确引用和指针,`decltype`辅助复杂类型推导,保持适度使用以维持代码清晰。
41 1
|
2月前
|
编译器 C++
【C++】类和对象⑤(static成员 | 友元 | 内部类 | 匿名对象)
📚 C++ 知识点概览:探索类的`static`成员、友元及应用🔍。
|
3月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
33 2
|
4月前
|
C++
C++中使用namespace关键字定义和访问命名空间的技术性探讨
C++中使用namespace关键字定义和访问命名空间的技术性探讨
31 3
|
3月前
|
Unix 编译器 C语言
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
20 0
|
3月前
|
存储 安全 编译器
【C++】:函数重载,引用,内联函数,auto关键字,基于范围的for循环,nullptr关键字
【C++】:函数重载,引用,内联函数,auto关键字,基于范围的for循环,nullptr关键字
26 0