当前位置: 首页 > news >正文

C语言---存储类

文章目录

  • 1. auto (自动存储类)
  • 2. register (寄存器存储类)
  • 3. static (静态存储类)
    • A. 静态局部变量(Static Local Variables)
    • B. 静态全局变量/函数(Static Global Variables/Functions)
  • 4. extern (外部存储类)

存储类是C语言中一个非常重要的概念,它用于规定变量/函数的作用域(Scope) 和生命周期(Lifetime)。
C语言中有四种主要的存储类说明符(Storage Class Specifiers):
1、auto
2、register
3、static
4、extern

1. auto (自动存储类)

关键字: auto
作用域: 局部(仅限于定义它的代码块内部,如函数内部、循环内部)。
生命周期: 自动的。当程序进入定义它的代码块时被创建,当退出该代码块时被自动销毁。每次进入代码块都会重新初始化(如果进行了初始化的话)。
存储位置: 内存的栈(Stack) 区。
注意: 所有局部变量默认的存储类,所以从不在代码中显式地写上 auto。auto 只能用在函数内,即 auto 只能修饰局部变量。

#include <stdio.h>void myFunction() {auto int x = 10; // 等价于 int x = 10;printf("x = %d\n", x);x++;
}int main() {myFunction(); // 输出:x = 10myFunction(); // 输出:x = 10 (每次调用都会重新创建和初始化x)return 0;
}

2. register (寄存器存储类)

关键字: register
存储位置: 建议编译器将变量存储在CPU的寄存器(Register) 中,而不是内存中,以期获得更快的访问速度。
重要限制: 量的最大尺寸等于寄存器的大小(通常是一个字),不能对 register 变量使用取地址运算符 &,因为寄存器没有内存地址。
注意: 这只是一个对编译器的建议(hint)。定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

void calculate() {register int counter; // 建议编译器将counter放入寄存器for(counter = 0; counter < 10000; counter++) {// 频繁使用的循环变量是使用register的典型场景}// int *p = &counter; // 错误!不能获取register变量的地址
}

提醒:
不建议用于全局变量。
原因有以下两点:
a. 寄存器是稀缺资源
CPU中的寄存器数量非常有限(通常只有几十个),而且它们被系统用于各种关键操作。将一个全局变量长期占用一个寄存器是不现实且低效的,编译器几乎肯定会拒绝这个请求。

b. 取地址操作符 & 不可用
这是最直接的技术原因。register 关键字明确暗示该变量可能没有内存地址(因为它住在寄存器里)。因此,你不能对 register 变量使用取地址操作符 &。

3. static (静态存储类)

static 关键字用途很广,根据它修饰的是局部变量还是全局变量,含义有所不同。

A. 静态局部变量(Static Local Variables)

作用域: 局部(仍然仅限于定义它的代码块内部)。

生命周期: 静态的。它在程序整个运行期间都存在,不会随着函数调用结束而销毁。它只被初始化一次,下次函数调用时会保持上一次调用结束时的值。

存储位置: 内存的数据段(Data Segment) 或 BSS段。

#include <stdio.h>void count() {static int c = 0; // 只初始化一次c++;printf("Count = %d\n", c);
}int main() {count(); // 输出:Count = 1count(); // 输出:Count = 2 (保留了上一次的值)count(); // 输出:Count = 3return 0;
}

B. 静态全局变量/函数(Static Global Variables/Functions)

作用域: 文件作用域(File Scope)。被 static 修饰的全局变量或函数,其作用域被限制在定义它的源文件内部,不能被其他源文件通过 extern 引用。

目的: 用于实现封装和隔离,避免大型项目中多个源文件之间的命名冲突。
示例(两个文件):

static int private_var = 50; // 只能被file1.c中的函数访问static void private_function() { // 只能被file1.c中的函数调用printf("This is private to file1.c\n");
}void public_function() {private_function();printf("Accessing private_var: %d\n", private_var);
}
extern void public_function(); // 可以,声明在file1.c中定义的全局函数// extern int private_var;      // 错误!无法链接到file1.c中的private_var
// void private_function();     // 错误!无法链接到file1.c中的private_functionint main() {public_function();return 0;
}

4. extern (外部存储类)

关键字: extern
用途: 用于声明一个在其他地方(通常是其他源文件)已经定义的全局变量或函数。它告诉编译器:“这个变量/函数存在,但定义在别处,你去链接的时候再找它的具体位置”。
作用域: 取决于它被声明的位置。如果是在函数内声明,则是块作用域;如果是在文件顶部声明,则是文件作用域。
生命周期: 整个程序运行期。
存储位置: 对于变量,位于数据段(Data Segment) 或 BSS段。
示例(两个文件):
global.h (头文件,可选)

extern int global_number; // 在头文件中声明外部变量
extern void display();    // 声明函数

file1.c (定义)

#include <stdio.h>
int global_number = 100; // 真正的定义,分配存储空间void display() {printf("Global number is %d\n", global_number);
}

file2.c (使用)

#include <stdio.h>
// #include "global.h" // 也可以包含头文件,效果等同于下面两行
extern int global_number; // 声明,不分配存储空间,只是引用
extern void display();    // 声明int main() {printf("%d\n", global_number); // 使用在file1.c中定义的变量display();                     // 调用在file1.c中定义的函数return 0;
}

文章转载自:

http://Ejwn71IQ.xnrgb.cn
http://5POGNpp3.xnrgb.cn
http://Z8fhlKjw.xnrgb.cn
http://HarPetAZ.xnrgb.cn
http://xA9Ty0Cv.xnrgb.cn
http://G4Qi079q.xnrgb.cn
http://AKhnnoZQ.xnrgb.cn
http://muwweuZ0.xnrgb.cn
http://Ww4EwmAc.xnrgb.cn
http://6EGB3SxQ.xnrgb.cn
http://7jp3KFwA.xnrgb.cn
http://TcvJN7GE.xnrgb.cn
http://6G7yQGs0.xnrgb.cn
http://NgAz5409.xnrgb.cn
http://IehdioxM.xnrgb.cn
http://7E2dqV1C.xnrgb.cn
http://GNcguNqi.xnrgb.cn
http://iOirxgWx.xnrgb.cn
http://1QBcDg5t.xnrgb.cn
http://oXH8nXxj.xnrgb.cn
http://yfIvr04B.xnrgb.cn
http://gp55BB5e.xnrgb.cn
http://EKEusNzy.xnrgb.cn
http://HIsVKTjw.xnrgb.cn
http://GBYlawCS.xnrgb.cn
http://mPQe8WGv.xnrgb.cn
http://rDrB5N5V.xnrgb.cn
http://OJn9P4ot.xnrgb.cn
http://ifNSZYNZ.xnrgb.cn
http://0s0w6jsx.xnrgb.cn
http://www.dtcms.com/a/381966.html

相关文章:

  • Windows 下 .venv 激活脚本深度定制:同时注入 PyTorch 调试日志与国内网络加速通道——从“能跑”到“好调”的完整工程化方案
  • 以表格形式,图像形式,函数形式来理解 概率质量函数(Probability Mass Function, PMF)
  • 解决前端部署版本追溯难题:vite-plugin-version-mark 实践
  • 【Linux网络】简易应用层协议定制
  • 剪/染前如何降低“想象错位”的风险:一次线上试发的记录(工具:RightHair)
  • 【数据结构与算法Trip第4站】摩尔投票法
  • Java的8 种基本类型 + 包装类,缓存池机制
  • AI 辅助完成复杂任务的亲身体验:使用Qoder 3 天完成 OneCode UI 升级
  • 二叉树基础学习(图文并茂)万字梳理
  • Qt 工程中 UI 文件在 Makefile 中的处理
  • Champ-基于3D的人物图像到动画视频生成框架
  • 深入探索 C++ 元组:从基础到高级应用
  • 第5节-连接表-Cross-Join连接
  • 2025年8月月赛 T2 T3
  • 在Linux上无法访问usb视频设备
  • AI行业应用全景透视:从理论到实践的深度探索
  • [硬件电路-192]:基级与发射极两端的电压超过1.5v可能是什么原因
  • OpenTenBase应用落地实践:从MySQL到OpenTenBase的平滑迁移
  • Redis常用数据结构及其底层实现
  • 深度卷积生成对抗网络
  • 打造精简高效的 uni-app 网络请求工具
  • 基于ZIGBEE的智能太阳能路灯系统设计(论文+源码)
  • Linux 磁盘I/O高占用进程排查指南:从定位到分析的完整流程
  • 20250913-02: Langchain概念:表达式语言(LCEL)
  • 【YOLO目标检测】获取COCO指标
  • React 18 过渡更新:并发渲染的艺术
  • node.js卸载并重新安装(超详细图文步骤)
  • 【CSS学习笔记3】css特性
  • k8s-Sidecar容器学习
  • 坦克大战的学习