文章

C 存储类

C 存储类

在 C 语言里,“存储类”(storage class)是一组关键字,用来指定变量或函数在程序中的存储位置、生命周期和可见性

主要回答三个问题:

  1. 变量/函数放在哪里?(存储位置:内存、寄存器、静态存储区等)
  2. 能活多久?(生命周期:函数执行期间还是整个程序期间)
  3. 谁能看见它?(作用域:当前文件、当前函数还是全局可见)

常见存储类关键字

存储类作用域(scope)生命周期(lifetime)存储位置默认初始化常见用途
auto代码块内(局部变量)代码块执行期间(函数调用到返回)未初始化(值不确定)默认局部变量,不常显式写
register代码块内(局部变量)代码块执行期间寄存器(建议性,现代编译器可忽略)未初始化高速访问变量(老代码常见)
static(局部)代码块内程序整个运行期间静态存储区自动初始化为 0保留函数内的值,下次调用继续使用
static(全局)当前文件程序整个运行期间静态存储区自动初始化为 0限制全局变量或函数只能在本文件使用
extern全局变量/函数(声明)程序整个运行期间静态存储区取决于定义处在其他文件引用外部变量或函数
_Thread_local(C11)线程内线程存活期间线程本地存储区未初始化每个线程有独立副本
static _Thread_local当前文件+线程内线程存活期间线程本地存储区自动初始化为 0线程私有且仅本文件可见

auto 存储类

auto 存储类是所有局部变量默认的存储类。

1
2
3
4
{
   int mount;
   auto int month;
}

上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量。

register 存储类

register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个字节),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。

1
2
3
{
   register int  miles;
}

寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 register 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

static 存储类

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
/* 函数声明 */
void func(void);
 
static int count = 5; /* 全局变量 */
 
main()
{
   while(count--)
   {
      func();
   }
   return 0;
}
/* 函数定义 */
void func( void )
{
   static int i = 5; /* 局部静态变量 */
   i++;

   printf("i is %d and count is %d\n", i, count);
}

extern 存储类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
 
int count ;
extern void write_extern();
 
main()
{
   count = 5;
   write_extern();
}
1
2
3
4
5
6
7
8
#include <stdio.h>
 
extern int count;
 
void write_extern(void)
{
   printf("count is %d\n", count);
}

在本例中,第二个文件中的 extern 关键字用于声明已经在第一个文件 main.c 中定义的 count

本文由作者按照 CC BY 4.0 进行授权