深入C语言:探究static关键字的奥秘

文章目录

  • 一、链接属性
  • 二、static变量
    • 1、定义静态局部变量
    • 2、在函数内部使用静态变量
    • 3、函数中静态局部变量与递归
  • 三、static变量与全局变量的区别
    • 1、存储期与生命周期
    • 2、可见性与作用域
    • 3、使用场景
    • 4、静态与动态内存分配
  • 注意事项

当用于不同的上下文环境时, static关键字具有不同的意思。

当用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的链接属性(从 external 变为 internal ),但标识符的存储类型和作用域不受影响。用这种方式声明的函数或变量只能在声明它们的源文件中访问。

当用于代码块内部的局部变量的声明的时候,static用于修改变量的存储类型,从自动变量修改为静态变量,但变量的链接属性和作用域不受影响。用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一直存在,而不是每次在代码块开始执行时创建,在代码块执行完毕之后销毁。

一、链接属性

链接属性一共有3种–external(外部)、internal(内部)和 none(无)。

  • 没有链接属性的标识符(none)总是被当作单独的个体,也就是说该标识符的多个声明被当作不同的独立实体。

  • 属于internal链接属性的标识符在同一个源文件内的所有声明中都指同一个实体,但位于不同源文件的多个声明则分属不同的实体。

  • 属于 external链接属性的标识符不论声明多少次,位于几个源文件都表示同一个实体。

关键字 externstatic用于在声明中修改标识符的链接属性。如果某个声明在正常情况下具有external链接属性,在它前面加上static关键字可以使它的属性变为internalstatic int a;那么变量a就将为这个源文件私有。其他源文件中,如果也链接到一个叫做变量 a 的变量,那么它所引用的是另一个不同的变量。类似的也可以把函数声明为 static

static int func(); 

这样可以防止被其他源文件调用。

extern 关键字的规则更为复杂。一般而言,它为一个标识符指定external链接属性,这样就可以访问在其他任何位置定义的这个实体。

具有 external属性的变量我们一般称之为全局变量,所有源文件中的所有函数均可以访问它。只要变量并非声明于代码块或函数定义内部,它在缺省的情况下的链接属性即为external。如果一个变量声明于代码块内部,在它前面添加extern关键字讲使它所引用的是全局变量而非局部变量。

具有 external链接属性的实体总是具有静态存储类型。全局变量在程序开始执行前创建,并在程序整个执行过程中始终存在。从属于函数的局部变量在函数开始执行时创建,在函数执行完毕后销毁,但用于执行函数的机器指令在程序的生命期内一直存在。

局部变量由函数内部使用,不能被其他函数通过名字引用。它在缺省情况下的存储类型为自动。这是基于两个原因:其一,当这些变量需要时才为它们分配存储,这样可以减少内存的总需求量;其二,在堆栈上为它们分配存储可以有效地实现递归。如果你觉得让变量的值在函数的多次调用中始终保持原先的值非常重要的话,那么可以修改它的存储类型,把它从自动变量改为静态变量。


二、static变量

在C语言中,当在函数内部定义static变量时,该变量具有静态存储期,这意味着该变量的生命周期将贯穿整个程序的执行过程,而不仅仅是局限于函数调用的局部范围。此外,静态局部变量只会被初始化一次,即在程序开始执行时,后续函数调用中不会再次初始化。由于这种特性,静态局部变量常用于在函数调用之间保持状态,如计数或累积数据。

1、定义静态局部变量

在函数内部,使用static关键字定义变量。

int main() {
    static int myStaticVar = 0; // 静态局部变量,只初始化一次
    // ... 函数的其他代码 ...
}

2、在函数内部使用静态变量

像使用普通局部变量一样使用静态局部变量,通过变量名进行访问和修改。可以在多次函数调用中保持状态,由于静态局部变量在函数调用之间保持其值,因此它们可用于跨函数调用维护状态。

void myFunction() {
    static int count = 0;
    count++; // 每次调用函数时,count增加1
    printf("Function has been called %d times.\n", count);
}

在这里插入图片描述

在上面的例子中,myFunction函数有一个静态局部变量count,它只会在程序开始时初始化一次。每次调用这个函数时,count都会递增,并且由于它是静态的,所以它的值会在函数调用之间保持。

需要注意的是:

  • 静态局部变量不会自动初始化为它们的默认值(比如int类型的0),除非显式地进行初始化。如果未初始化,它们将包含未定义的值。
  • 静态局部变量不会占用函数每次调用时的栈空间,因为它们的存储期是整个程序的执行期间,通常存放在程序的数据段中。
  • 在多线程环境中,静态局部变量可能不是线程安全的,因为所有线程共享同一份静态变量的存储。如果需要跨线程保持状态,应使用线程安全的机制,如互斥锁(mutex)或原子操作。

所有不加static的全局变量和函数具有全局可见性,可以在其他文件中使用;加了static之后只能在该文件所在的编译模块中使用。

在这里插入图片描述

一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

在这里插入图片描述

在C语言中,static关键字在函数调用中的主要用法是用于声明函数内部的局部变量,使其具有静态存储期。这意味着这些局部变量不会在函数调用结束时被销毁,而是会保留其值,直到程序结束。这在需要跨函数调用保留状态时特别有用。(注意:main函数所在文件需声明 add函数。)

3、函数中静态局部变量与递归

在递归函数中,static局部变量也很有用,因为它们可以在递归调用之间保持其值。例如,下面是一个计算阶乘的递归函数:

unsigned long long factorial(int n) {
    static unsigned long long result = 1; // 静态局部变量用于累积结果
    if (n > 0) {
        result *= n;
        return factorial(n - 1); // 递归调用
    } else {
        return result; // 返回累积的结果
    }
}

在这个例子中,result是一个static局部变量,用于在递归调用之间累积阶乘的结果。如果没有static关键字,每次递归调用都会创建一个新的局部变量result,导致结果不正确。


三、static变量与全局变量的区别

1、存储期与生命周期

全局变量:全局变量在程序开始执行时分配内存,并在整个程序的执行期间都保持其存在。无论函数是否被调用,全局变量都占据内存空间,并在程序结束时释放其内存。

static变量:无论是全局还是局部,static变量都具有静态存储期。这意味着它们在程序开始执行时分配内存,并且在程序的整个执行期间都存在。对于static局部变量来说,这是一个关键区别,因为普通的局部变量只在函数被调用时存在,并在函数返回时释放其内存。

2、可见性与作用域

全局变量:全局变量的作用域是整个程序,这意味着它们可以在任何函数内部被访问和修改(除非被同名的局部变量覆盖)。同时,由于它们具有外部链接属性,它们可以在其他文件中通过extern声明被引用。

static全局变量:尽管它们在存储期上与全局变量相同,但static关键字改变了它们的可见性。static全局变量仅在其定义的文件中可见,即使其他文件包含了相应的头文件,也无法直接访问它们。这是因为static全局变量具有内部链接属性,使得它们的链接仅限于定义它们的文件。

static局部变量:这些变量在函数内部定义,其作用域仅限于该函数。但是,由于它们的静态存储期,它们的值在函数调用之间保持不变。这意味着每次函数被调用时,它都会看到上次调用时留下的static局部变量的值。

3、使用场景

全局变量:全局变量通常用于需要在多个函数或文件之间共享的数据。然而,过度使用全局变量可能导致代码难以理解和维护,因为它们可以被程序的任何部分修改。

static变量static全局变量通常用于限制变量的可见性,以避免命名冲突和提高代码模块的独立性。static局部变量则常用于需要在函数调用之间保持状态的场景,如计数器或累加器。

总结来说,static变量和全局变量在存储期、可见性、作用域、初始化以及使用场景方面存在显著的区别。选择使用哪种类型的变量取决于具体的应用需求和编程风格。在编写代码时,应该谨慎考虑变量的存储期和可见性,以确保程序的正确性和可维护性。

4、静态与动态内存分配

static并不直接涉及动态内存分配(如mallocfree),但理解静态和动态内存分配的不同是很重要的。静态变量在编译时分配内存,而动态内存分配在运行时进行。


注意事项

  • static局部变量只在定义它们的函数内部可见,它们不是全局变量。
  • static局部变量只会被初始化一次,即使函数被多次调用。
  • static变量在程序的整个执行期间都存在,这意味着它们会占用内存,直到程序结束。因此,过度使用static局部变量可能会导致内存浪费。

总结来说,static在函数调用中的主要用法是定义具有静态存储期的局部变量,以便在函数调用之间保留其值。这在需要跨函数调用保留状态或累积数据的场景中特别有用。

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

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

相关文章

nginx配置多vue项目

1. 找到linux docker安装好的nginx目录文件 进入nginx内 把打包好的vue项目放在html文件下 如上 三个文件夹下对应着三个不同的vue项目 2. 配置default.conf的配置文件, 一个nginx配置文件可以多个项目进行代理 进入到conf 找到conf.d下面的default.conf 文件…

Springboot自动获取接口实现

ServiceLoader加载接口实现步骤 1.编写接口 public interface CommunicationAdapterFactory {void setKernel(LocalKernel kernel);boolean providesAdapterFor(Vehicle vehicle);BasicCommunicationAdapter getAdapterFor(Vehicle vehicle); }2.编写实现 // 实现类 1 publi…

EasyBoss ERP支持TikTok Shop拆单发货功能,多店铺订单包裹拆分一个系统搞定

一些TikTok Shop本土卖家在运营过程中面临这样的困境:当顾客一次性订购多个商品,由于部分商品缺货或包裹超重,订单延迟发货或被物流限制发不出货,导致店铺被投诉。为了解决这一问题,卖家可以采取拆单发货的策略&#x…

支持各种不同系列nvdia显卡和amd显卡,DeepFaceLab安装与使用,附完整的软件打包下载一键安装

支持各种不同系列nvdia显卡和amd显卡,DeepFaceLab安装与使用,附完整的软件打包下载一键安装。 主要使用的技术: 1. 深度学习(Deep Learning) 深度学习是人工智能领域的一个重要分支,它通过模拟人脑的神经…

蓝桥杯 - 正则问题

解题思路: dfs import java.util.Scanner;public class Main {static int pos -1; // 充当charAt下标static String s;// 字符串型的静态变量public static void main(String[] args) {Scanner scanner new Scanner(System.in);s scanner.nextLine();System.ou…

Spring Boot--文件上传和下载

文件上传和下载 前言文件上传1、以MultipartFile 接口流文件,流的名称需要和前台传过来的名称对应上2、获取到文件名称截取后缀3、为了放置文件名重复使用uuid来随机生成id后缀4、判断转存路径中是否有这个文件夹如果没有就创建5、将文件存储到转存的目录中 文件下载…

免费AI视频工具PixVerse厉害了:可保持人物超强一致性(附详细教程)

PixVerse 上线了「Character」,可以在更换场景的情况下,保持人物的一致性。 下面就是用创建的人物角色,生成的不同场景下(海边、城市街道、教室)的视频,整体看一致性程度还是超出我的预期的。 PixVerse 人物…

华为服务器RAID配置教程 服务器硬盘故障处理帮助 浪潮RAID配置教程 磁盘阵列配置通用教程

前言(本文档持续更新) 本文主要记录服务器配置RAID(磁盘阵列)过程中存在的细节问题及官方文档无法解决的问题的解决方案 配置环境 华为 RH2288 v3服务器配置RAID组 如何快速配置 1.找到服务器品牌的阵列卡型号,找不到…

DBU-Net:用于乳腺超声图像中肿瘤分割的双分支U形网络

DBU-Net:用于乳腺超声图像中肿瘤分割的双分支U形网络 摘要引言材料和方法概述所提出的方法 DBU-Net Dual branch U-Net for tumor segmentation in breast ultrasound images 摘要 乳腺超声医学图像通常具有低成像质量沿着不清楚的目标边界。这些问题使得医生在诊断…

详解k8s集群内外的访问方式

文章目录 1、集群内访问2、集群外访问2.1、Ingress转发外网请求2.2、LoadBanlancer接入外网请求2.3、NodePort接入外网请求 3、总结和对比3.1、Ingress、NodePort和LoadBalancer总结3.2、Ingress和网关的区别 1、集群内访问 在k8s中创建的微服务,大部分都是在集群内…

收下这份地表最强参会指南,4月16日,玩转百度Create大会不迷路

欢迎来到英杰社区: https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区: https://bbs.csdn.net/topics/617897397 📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步&#xff…

短视频素材怎么做?探索新鲜网站获取灵感

在短视频创作的过程中,寻找和制作高质量的素材是至关重要的。那么,短视频素材怎么做呢?让我们一起探索一些新鲜的网站,获取灵感和素材,让你的短视频作品更加别出心裁! 蛙学网——中国 国内首推荐蛙学网&a…

dm控制台工具console

DM控制台工具console console工具介绍 DM控制台工具是管理和维护数据库的基本工具。 通过使用控制台工具,数据库管理员可以完成以下功能: ◆服务器参数配置 ◆管理DM服务 ◆脱机备份与还原 ◆查看系统信息 ◆查看许可证信息 一 登录console [dmdbatest1 tool]$ pwd…

3.java openCV4.x 入门-数据类型(CvType)与Scalar

专栏简介 💒个人主页 📰专栏目录 点击上方查看更多内容 📖心灵鸡汤📖我们唯一拥有的就是今天,唯一能把握的也是今天 🧭文章导航🧭 ⬆️ 2.hello openCV ⬇️ 4.待更新 数据类型&#xff…

【算法】字典序超详细解析(让你有一种相见恨晚的感觉!)

目录 一、前言 二、什么是字典序 ? ✨字典序概念 ✨深度理解字典序 ✨字典序排序的重要性和应用场景 三、常考面试题 ✨ 下一个排列 ✨ 字典数排序 ✨ 字典序最小回文串 四、共勉 一、前言 经常刷算法题的朋友,肯定会经常看到题目中提到 字典序 这样…

AutoMQ 如何实现分区持续重平衡?

01 引言 在一个线上 Kafka 集群中,流量的波动、Topic 的创建和删除、Broker 的消亡和启动都随时可能发生,而这些变化可能导致流量在集群各个节点间分布不均,从而导致资源浪费、影响业务稳定。此时则需要主动将 Topic 的不同分区在各个节点间…

mysql 磁盘空间100%

MySQL大事务可能会导致过多的占用临时文件,导致磁盘空间撑满的问题 本例说明下binlog cache产生的临时文件 案例复现 调小binlog_cache_size,让DML使用临时文件 使用存储过程模拟大事务 创建表 create table t1( id int AUTO_INCREMENT, name varchar…

[蓝桥杯练习]通电

kruskal做法(加边) #include <bits/stdc.h> using namespace std; int x[10005],y[10005],z[10005];//存储i点的x与y坐标 int bcj[10005];//并查集 struct Edge{//边 int v1,v2; double w; }edge[2000005]; int cmp(Edge a, Edge b){return a.w < b.w;} int find(i…

视频素材库哪个网站最好?推荐六大视频素材库

大家好&#xff01;在视频创作的旅程中&#xff0c;找到一个好的视频素材库就像找到了一把打开宝藏的钥匙。那么&#xff0c;视频素材库哪个网站最好呢&#xff1f;今天&#xff0c;我要给大家推荐六个主流的视频素材分享网站&#xff0c;让你的视频制作更加轻松&#xff0c;在…

Goby 漏洞发布|浙大恩特客户资源管理系统 RegulatePriceAction SQL 注入漏洞

漏洞名称&#xff1a; 浙大恩特客户资源管理系统 RegulatePriceAction SQL 注入漏洞 English Name&#xff1a; Entsoft Duite Customer Resource Management System RegulatePriceAction API SQL Injection Vulnerability CVSS core: 9.3 影响资产数&#xff1a;10524 漏洞…