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;
}