[c/c++] static 关键字

从修饰的对象来看,static 可以修饰局部变量,也可以修饰全局变量,可以修饰函数;可以修饰类中的成员变量以及成员函数。

从生命周期的角度来看,static 修饰的对象的生命周期,与进程的生命周期是一致的。

从作用域的角度来看,局部静态变量的作用域是函数内,全局静态变量的作用域是模块内;类中的静态成员变量和成员函数的作用域,能访问到类的地方都可以访问到静态成员,类中的静态成员同时也受 public,private,protected 权限修饰符的影响。在 c 语言中,静态函数的作用域只在模块内,这样也是一种权限管理,不让其它模块来访问,增强了安全性;同时,多个模块中的两个静态函数的函数名也可以是相同的,给开发带来了方便。

1 static 修饰变量

1.1 局部静态变量

如下代码,在函数 Test() 中声明定义了一个静态变量 static int a = 10,局部静态变量有以下 3 点需要注意:

(1)作用域是函数内

(2)在 static int a = 10,只在启动的时候初始化一次,不像普通的变量,Test() 每次调用的时候都会将 a 赋值成 10。代码中的 a++ 分别是 11,12,13 ...

(3)在声明的时候需要初始化,并且初始化的值必须得是确定的

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void Test(int data) {
  // static int a = data; // 这样编译不过,编译的时候就需要确定  error: initializer element is not constant
  static int a = 10;
  a++;
  printf("a = %d, data = %d\n", a, data);
}

int main() {
  for (int i = 0; i < 10; i++) {
    Test(i);
  }
  return 0;
}

运行结果如下:

1.2 全局静态变量

在 c 语言中,全局静态变量的作用域就是在源文件内,一个 c 文件中的函数无法访问到另一个 c 文件中声明的静态全局变量。

文件 s0.c 中定义一个静态变量:

static int static_ele = 100;

文件 s0.h 中使用 extern 声明了这个变量:

extern int static_ele;

文件 s2.c 中包含了头文件 s0.h,并且尝试访问变量 static_ele。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s0.h"

static int a = 100;

int main() {
  printf("a = %d, static_ele = %d\n", a, static_ele);
  return 0;
}

编译会报错,在 s2.c 中无法访问到 static_ele。

2 static 修饰函数

static 修饰的函数也是只能在 c 文件内部访问,在其它 c 文件不能访问。
 

文件 s3.c 中定义一个静态函数 static void SayHello():

#include <stdlib.h>
#include <stdio.h>

static void SayHello() {
  printf("hello in static function\n");
}

void SayHello1() {
  printf("hello1\n");
}

文件 s3.h 中是函数的声明:

void SayHello();
void SayHello1();

文件 s4.c 中包含了头文件 s3.h,并尝试调用函数 SayHello():

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s3.h"

int main() {
  SayHello();
  SayHello1();
  return 0;
}

 编译报错,找不到函数定义:

在 c 语言中,经常使用函数指针,如果静态函数被一个函数指针维护,那么其它模块可以通过函数指针来调用静态函数的。static 关键字是编译阶段检查的语法,在运行时无法检查。

对 s3.c,s3.h,s4.c 进行修改,使用一个函数指针来保存静态函数 SayHello() 的地址,这样的话只要能拿到这个函数指针,就能调用对应的函数。

s3.c:

#include <stdlib.h>
#include <stdio.h>
#include "s3.h"

static void SayHello() {
  printf("hello in static function\n");
}

void SayHello1() {
  printf("hello1\n");
}

struct FunctionPointer fp = {
  .say_hello = SayHello
};

s3.h

void SayHello1();

struct FunctionPointer {
  void (*say_hello)();
};

extern struct FunctionPointer fp;

s4.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s3.h"

int main() {
  fp.say_hello();
  SayHello1();
  return 0;
}

编译运行结果如下:

3 static 修饰类成员

3.1 静态成员变量

静态成员变量属于类,不属于对象。所有的对象共享一份静态成员变量,而不是每个对象都拥有一个。

静态成员变量有以下几点需要注意,在代码中通过注释做了说明。

(1)需要在类外初始化

(2)在类外初始化的时候不能使用 static 修饰

(3)静态成员变量可以被 public,private,protected 修饰,访问权限与非静态成员变量是一致的

#include <iostream>
#include <string>

class Test {
public:
  Test() {
    std::cout << "Test()" << std::endl;
    public_a = 1;
    private_a = 2;
    protected_a = 3;
  }

  ~Test() {
    std::cout << "~Test()" << std::endl;
  }

  void Do() {
    std::cout << "public a = " << public_a << std::endl;
    std::cout << "private a = " << private_a << std::endl;
    std::cout << "protected a = " << protected_a << std::endl;
  }

  static int public_a;

private:
  static int private_a;

protected:
  static int protected_a;
};

// 类的静态成员变量在类外初始化的时候
// 不能再加 static 关键字
// 如果还带 static 关键字,会报错
// error: ‘static’ may not be used when defining (as opposed to declaring) a static data member
// static int Test::public_a = 10;
// static int Test::private_a = 20;
// static int Test::protected_a = 30;

// 类的静态成员变量需要在类外初始化
int Test::public_a = 10;
int Test::private_a = 20;
int Test::protected_a = 30;

int main() {
  Test t;
  t.public_a = 100;
  t.Do();
  // t.private_a = 200;
  // t.protected_a = 300;
  Test::public_a = 1000;
  // Test::private_a = 200;
  // Test::protected_a = 300;
  t.Do();
  return 0;
}

 运行结果如下图所示:

3.2 静态成员函数

静态成员函数有以下几点需要注意:

(1)可以在类内部声明和实现

(2)也可以在类内部声明,在类外部实现,在类外部实现时,不能 static 修饰

(3)静态成员函数中不能调用非静态成员函数,也不能使用非静态成员变量,因为静态函数中没有 this 指针

#include <iostream>
#include <string>

class Test {
public:
  Test() {
    std::cout << "Test()" << std::endl;
    public_a = 1;
    private_a = 2;
    protected_a = 3;
  }

  ~Test() {
    std::cout << "~Test()" << std::endl;
  }

  void Do() {
    std::cout << "public a = " << public_a << std::endl;
    std::cout << "private a = " << private_a << std::endl;
    std::cout << "protected a = " << protected_a << std::endl;
  }

  static void StaticDo() {
    // Do(); // error: cannot call member function ‘void Test::Do()’ without object
    // public_b = 10; // error: invalid use of member ‘Test::public_b’ in static member function
    public_a = 10;
    std::cout << "StaticDo" << std::endl;
  }

  static void StaticDo1();

  static int public_a;
  int public_b;

private:
  static int private_a;

  static void PrivateStaticDo() {
    std::cout << "Private StaticDo" << std::endl;
  }

protected:
  static int protected_a;

  static void ProtectedStaticDo() {
    std::cout << "Protected StaticDo" << std::endl;
  }
};

int Test::public_a = 10;
int Test::private_a = 20;
int Test::protected_a = 30;

// error: cannot declare member function ‘static void Test::StaticDo1()’ to have static linkage
/* static */ void Test::StaticDo1() {
  std::cout << "StaticDo1()" << std::endl;
}

int main() {
  Test t;
  t.StaticDo();
  t.StaticDo1();
  // t.PrivateStaticDo();
  // t.ProtectedStaticDo();
  // Test::PrivateStaticDo();
  // Test::ProtectedStaticDo();
  return 0;
}

代码运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/412763.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv7代码解读[01] readme解读

模型性能 安装 # create the docker container, you can change the share memory size if you have more. nvidia-docker run --name yolov7 -it -v your_coco_path/:/coco/ -v your_code_path/:/yolov7 --shm-size64g nvcr.io/nvidia/pytorch:21.08-py3# apt install requir…

如果使用npm无法下载模块依赖,那么你可以尝试一下这个方法

问题复现 如果执行&#xff0c;npm install XXXX&#xff0c;出现了无法安装&#xff0c;一直等待&#xff0c;如何解决&#xff1f; 解决方法 1.先查看npm配置 npm config ls2.设置prefix和cache&#xff08;可选&#xff09; 指定到node安装目录 npm config set prefix …

【QT+QGIS跨平台编译】之五十一:【QGIS_CORE跨平台编译】—【qgsexpressionparser.cpp生成】

文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…

Netwalker勒索病毒服务私有化,只攻击目标企业

前言 2020年勒索病毒攻击出现了一些新的发展趋势&#xff0c;一些勒索病毒黑客组织将目标对准了一些国内外明星&#xff0c;网红博主等&#xff0c;还有一些勒索病毒黑客组织将自己的RAAS平台私有化&#xff0c;像之前比较流行的NEMTY勒索病毒黑客组织&#xff0c;就公开声称将…

LeetCode刷题--- 环形子数组的最大和

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述动…

Qt QWidget 简约美观的加载动画 第五季 - 小方块风格

给大家分享两个小方块风格的加载动画 &#x1f60a; 第五季来啦 &#x1f60a; 效果如下: 一个三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QGridLayout> int main(int argc, char *arg…

vulnhub----hackme2-DHCP靶机

文章目录 一&#xff0c;信息收集1.网段探测2.端口扫描3.目录扫描 二&#xff0c;信息分析三&#xff0c;sql注入1.判断SQL注入2.查询显示位3.查询注入点4.查询库5.查询表6.查字段7. 查user表中的值8.登陆superadmin用户 四&#xff0c;漏洞利用文件上传命令执行蚁剑连接 五&am…

SwiftUI中的 WebView

SwiftUI中的WebView是一个用于显示网页内容的视图。它是使用WebKit框架的一个封装。 要在SwiftUI中使用WebView&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;导入WebKit框架&#xff1a; import WebKit创建一个WebView实例&#xff1a; struct WebView…

将文件从windows传入到ubuntu

实现效果图 2.方法&#xff1a; 2.1打开 Ubuntu 的终端窗口&#xff0c;然后执行如下命令来安装 FTP 服务 输入&#xff1a;sudo apt-get install vsftpd 等待软件自动安装&#xff0c;安装完成以后使用如下 VI 命令打开/etc/vsftpd.conf&#xff0c;命令如下&#xff1a;su…

qt5.15 升级 qt 6.5 部分问题 解决修复

报错 QT5_USE_MODULES 升级 QT6_ADD_RESOURCES qt_add_resources Compiles binary resources into source code. CMake Commands in Qt6 Core | Qt Core 6.6.2

CrossOver24.0新功能介绍以及2024使用激活教程

CrossOver24简介 CrossOver 24.0 Mac/Linux版是一款功能强大的类虚拟机软件。CrossOver 24.0 for Mac/Linux软件能够帮助在Mac/Linux系统上使用Windows系统所支持的软件&#xff0c;实现各个系统之间的无缝集成。通过crossover 24.0软件用户可以进行跨平台的复制粘贴和文件互通…

刷题日记 | 字符串扩容和增强型for循环

for(char c:s)遍历字符串 增强型for循环 C for(char c:s)遍历字符串 增强型for循环_c for (char c : s)-CSDN博客 字符串使用前要进行扩容 reserve函数 【CString类成员函数辨析】resize(),size(),capacity(),reserve()函数的解析与对比_c reserve函数-CSDN博客 a.size() 用来…

ES小总结

组合查询 FunctionScoreQueryBuilder functionScoreQuery QueryBuilders.functionScoreQuery(boolQuery,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD",true),Score…

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库 Q&#xff1a;顺丰科技2024届校园招聘面向对象是&#xff1f; A&#xff1a;2024届应届毕业生&#xff0c;毕业时间段为2023年10月1日至2024年9月30日&#xff08;不满足以上毕业时间的同学可以关注顺丰科技社会招聘或…

代码随想录算法训练营第四一天 | 背包问题

目录 背包问题01背包二维dp数组01背包一维 dp 数组&#xff08;滚动数组&#xff09;分割等和子集 LeetCode 背包问题 01背包 有n件物品和一个最多能背重量为 w 的背包&#xff0c;第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#x…

5Why分析法不会用?别担心,精益企业管理咨询公司助你解锁新技能

近年来&#xff0c;为了保持竞争力&#xff0c;许多企业开始转向精益管理&#xff0c;而5Why分析法则是实现这一目标的关键工具之一。然而&#xff0c;对于许多初学者来说&#xff0c;5Why分析法可能显得陌生和复杂。今天&#xff0c;天行健精益企业管理咨询公司就来分享如何运…

NoSQL数据库介绍

目录 一、发展历史 二、什么是NoSQL&#xff1f; 三、为什么使用NoSQL&#xff1f; 四、NoSQL vs. RDBMS 五、NoSQL的四种类型 键值存储 文档存储 列式存储 图形存储 六、NoSQL的优缺点 七、NoSQL的特点 灵活的可扩展性 灵活的数据模型 与云计算紧密融合 大数据量…

Python爬虫中的单线程、多线程问题(文末送书)

前言 在使用爬虫爬取数据的时候&#xff0c;当需要爬取的数据量比较大&#xff0c;且急需很快获取到数据的时候&#xff0c;可以考虑将单线程的爬虫写成多线程的爬虫。下面来学习一些它的基础知识和代码编写方法。 一、进程和线程 进程可以理解为是正在运行的程序的实例。进…

【沐风老师】3DMAX快速布尔插件使用方法讲解

3DMAX快速布尔插件FastBool使用教程 3DMAX快速布尔插件FastBool&#xff0c;是一个基于布尔运算的小型但功能非常强大的插件。工作方便快捷。 【版本要求】 3dMax2017-2024&#xff08;不仅限于此范围&#xff09; 【安装方法】 该插件无需安装&#xff0c;使用时直接拖动插件…

使用 Verilog 做一个可编程数字延迟定时器 LS7211-7212

今天的项目是在 Verilog HDL 中实现可编程数字延迟定时器。完整呈现了延迟定时器的 Verilog 代码。 所实现的数字延迟定时器是 CMOS IC LS7212&#xff0c;用于生成可编程延迟。延迟定时器的规格可以在这里轻松找到。基本上&#xff0c;延迟定时器有 4 种操作模式&#xff1a;…