C 存储类

C 存储类

存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C 程序中可用的存储类:

  • auto
  • register
  • static
  • extern

auto 存储类

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

{
   int mount;
   auto int month;
}

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

register 存储类

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

{
   register int  miles;
}

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

static 存储类

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

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

static 是全局变量的默认存储类,以下两个变量 (count 和 road) 都有一个 static 存储类。

static int Count;
int Road;

main()
{
    printf("%d\n", Count);
    printf("%d\n", Road);
 }

以下实例演示了 static 修饰全局变量和局部变量的应用:

实例

#include <stdio.h>

/* 函数声明 */
void func1(void);

static int count=10;        /* 全局变量 - static 是默认的 */

int main()
{
  while (count--) {
      func1();
  }
  return 0;
}

void func1(void)
{
/* ‘thingy‘ 是 ‘func1‘ 的局部变量 - 只初始化一次
 * 每次调用函数 ‘func1‘ ‘thingy‘ 值不会被重置。
 */
  static int thingy=5;
  thingy++;
  printf(" thingy 为 %d , count 为 %d\n", thingy, count);
}

实例中 count 作为全局变量可以在函数内使用,thingy 使用 static 修饰后,不会再每次调用时重置。

可能您现在还无法理解这个实例,因为我已经使用了函数和全局变量,这两个概念目前为止还没进行讲解。即使您现在不能完全理解,也没有关系,后续的章节我们会详细讲解。当上面的代码被编译和执行时,它会产生下列结果:

 thingy 为 6 , count 为 9
 thingy 为 7 , count 为 8
 thingy 为 8 , count 为 7
 thingy 为 9 , count 为 6
 thingy 为 10 , count 为 5
 thingy 为 11 , count 为 4
 thingy 为 12 , count 为 3
 thingy 为 13 , count 为 2
 thingy 为 14 , count 为 1
 thingy 为 15 , count 为 0

extern 存储类

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

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

extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:

第一个文件:main.c

实例

#include <stdio.h>

int count ;
extern void write_extern();

main()
{
   count = 5;
   write_extern();
}

第二个文件:support.c

实例

#include <stdio.h>

extern int count;

void write_extern(void)
{
   printf("count is %d\n", count);
}

在这里,第二个文件中的 extern 关键字用于声明已经在第一个文件 main.c 中定义的 count。现在 ,编译这两个文件,如下所示:

 $ gcc main.c support.c

这会产生 a.out 可执行程序,当程序被执行时,它会产生下列结果:

count is 5

笔记列表

  1. auto 是局部变量的默认存储类, 限定变量只能在函数内部使用;

    register 代表了寄存器变量,不在内存中使用;

    static是全局变量的默认存储类,表示变量在程序生命周期内可见;

    extern 表示全局变量,即对程序内所有文件可见,类似于Java中的public关键字;

  2. C 语言中全局变量、局部变量、静态全局变量、静态局部变量的区别

    从作用域看:

    1、全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

    2、静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

    3、局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

    4、静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

    从分配内存空间看:

    1、全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

    2、全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

    • 1)静态变量会被放在程序的静态数据存储区(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
    • 2)变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

    从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。

    Tips:

    • A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
    • B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
    • C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
    • D.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带"内部存储器"功能的的函数)
    • E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
  3. auto 普通局部栈变量,是自动存储,这种对象会自动创建和销毁 ,建议这个变量要放在堆栈上面,调用函数时分配内存,函数结束时释放内存。一般隐藏auto默认为自动存储类别。我们程序都变量大多是自动变量。

    实例 auto.c

    #include <stdio.h>
    
    int main(void)
    {
        auto int i = 9; /* 声明局部变量的关键字是 auto; 因可以省略, 几乎没人使用 */
        printf("%d\n", i);
        getchar();
        return 0;
    }

    Register变量:动态和静态变量都是存放在内存中,程序中遇到该值时用控制器发指令将变量的值送到运算器中,需要存数再保存到内存中。如果频繁使用一个变量,比如一个函数体内的多次循环每次都引用该局部变量,我们则可以把局部变量的值放到CPU的寄存器中,叫寄存器变量。不需要多次到内存中存取提高效率。但是只能局部自动变量和形参可以做寄存器变量。在函数调用时占用一些寄存器,函数结束时释放。不同系统对register要求也不一样,比如对定义register变量个数,数据类型等限制,有的默认为自动变量处理。所以在程序一般也不用。

    实例 register.c

    #include <stdio.h>
    #include <time.h>
    
    #define TIME 1000000000
    int m, n = TIME; /* 全局变量 */
    
    int main(void)
    {
        time_t start, stop;
        register int a, b = TIME; /* 寄存器变量 */
        int x, y = TIME;          /* 一般变量   */
    
        time(&start);
        for (a = 0; a < b; a++);
        time(&stop);
        printf("寄存器变量用时: %ld 秒\n", stop - start);
    
        time(&start);
        for (x = 0; x < y; x++);
        time(&stop);
        printf("一般变量用时: %ld 秒\n", stop - start);
    
        time(&start);
        for (m = 0; m < n; m++);
        time(&stop);
        printf("全局变量用时: %ld 秒\n", stop - start);
    
        return 0;
    }

    输出结果:

    寄存器变量用时: 1 秒
    一般变量用时: 8 秒
    全局变量用时: 9 秒
时间: 2024-08-29 21:54:51

C 存储类的相关文章

存储类、链接、内存管理

作用域:代码块作用域.函数原型作用域.文件作用域 函数作用域(只适用于goto) 链接:外部链接.内部链接.空链接(代码块作用域.函数原型作用域) 存储时期:静态存储时期.自动动态存储时期 五种存储类:自动,寄存器(代码块内使用register,不能使用地址运算符),外部链接的静态.内部链接的静态(static).空链接 x =30;while(x++<33){ int x = 100; printf("%d",x); } 打印了三次100,递增必须在条件判断语句中 对函数参量不

c语言中用户标识符的作用域和存储类(2)

2 局部变量及其作用域和生存期 2.1 auto变量 当在函数内部或复合语句内定义变量时,如果没有指定存储类,或使用auto说明符,系统默认所定义的变量为自动类别.因此: float a; 等价于 auto float a; auto变量的存储单元被分配在内存的动态存储区.当进入函数体时,系统自动为auto变量分配存储单元:退出时自动释放这些存储单元.这类局部变量的作用域是从定义的位置起,到函数体结束为止.由于函数的频繁调用,动态存储区内为某个变量分配的存储单元位置随程序的运行而改变,变量的初值

ISO/IEC 9899:2011 条款6.7.1——存储类说明符

6.7.1 存储类说明符 语法 1.storage-class-specifier: typedef extern static _Thread_local auto register 约束 2.在一个声明中,在声明说明符中最多只能给出一个存储类说明符,除了_Thread_local可以与static或extern一起出现.[注:见“未来语言方向”(6.11.5)] 3.在含有语句块作用域的一个对象的声明中,如果声明说明符包含了_Thread_local,那么它们应该也包含static或是ext

C存储类、链接小结

参考<C Primmer Plus> 首先唠唠C语言关键字: 数据类型14个:            void,  char(1字节),  int(4字节), short(2字节),  long(4字节),  signed(4字节), unsigned(4字节),            float(4字节),  double(8字节),  struct, union, enum, typedef, sizeof 存储类控制类型6个:            auto, static, exter

C语言笔记之存储类

在C语言中,一个数据对象(往往是指变量)可以由3种属性来描述:作用域,存储时期,链接.每种属性有不同的值,这些不同值的组合构成数据对象的存储模型,又称为存储类,即,一个数据对象如何存在于计算机中.以下描述中,我们以变量为例(另一个例子是函数)代表数据对象. 一.作用域 作用域属性描述了一个数据对象可以在(源代码的)哪些区域被访问,它有以下几个值:代码块.函数原型.文件. 1.文件作用域 函数是C源代码文件的基本组织单位,但是如果一个变量定义在所有函数之外,即没有在任何一个函数体内,那么该变量就具

5种存储类

存储类 时期 作用域 链接 声明方式 自动 自动 代码块 空 代码块内 寄存器 自动 代码块 空 代码块内,使用关键字register 具有外部链接的静态 静态 文件 外部 所有函数之外 具有内部链接的静态 静态 文件 内部 所有函数之外,使用关键字static 空链接的静态 静态 代码块 空 代码块内,使用关键字static

C Primer Plus之存储类、链接和内存管理

存储时期即生存周期——变量在内存中保留的时间 变量的作用域和链接一起表明程序的哪些部分可以通过变量名来使用该变量. 注意:生存期和作用域是两个不同的概念. 作用域    作用域描述了程序中可以访问一个标识符的一个或多个区域.一个C变量的作用域可以是代码块作用域.函数原型作用域,或者文件作用域. 在代码块中定义的变量具有代码块作用域,从该变量被定义的地方到包含该定义的代码块的末尾该变量均可见.其次,函数的形式参量尽管在函数的开始花括号前进行定义,同样也具有代码块作用域,隶属于包含函数体的代码块.

CPrimer Plus第12章 存储类、链接和内存管理随笔

被static修饰的属于内部链接,不可被外部程序文件所使用一般而言,全局变量(文件作用域变量)具有静态存储期,局部变量(代码块作用域变量)具有自动存储期寄存器变量不能使用地址运算符因为被static修饰的变量不会中途被释放,所以不能用static修饰函数的形参变量的定义放在所有函数定义的外部即创建了一个外部变量,若外部变量在其他文件中定义,则需见extern修饰全局变量只能用常量表达式来赋值:int i;    int j = 2*i;不被允许 ptd = (double *)malloc(n

C语言--存储类、链接和内存管理

注:此文为<C Primer Plus>一书中的部分总结,写下来方便以后参考. 用于存储程序数据的内存可用存储时期.作用域和链接来表征. 存储时期可以使静态的.自动的或者分配的.①如果是静态的,内存在程序开始执行时被分配,并行程序运行时一直存在.②如果是自动的,变量所用内存在程序执行到该变量定义所在代码块时开始分配,在退出代码块时释放.③如果是分配的内存,内存通过调用malloc()(或其他相关函数)分配,通过调用函数free()释放. 作用域决定哪一部分程序可以访问某个数据.在所有函数之外定

存储类、作用域、生命周期、链接属性

1.linux下C语言程序的内存映像代码段(.text).数据段(.data).bss段.栈.堆的概念 代码段(.text) (1)对应着程序中的代码(函数),代码段在linux中又叫文本段(.text)(2)部分平台下的const修饰的变量. 数据段(.data) 1.显式初始化为非0的全局变量: 2.显式初始化为非0的static局部变量 bss段 1.显式初始化为0或者未显式初始化的全局变量: 2.显式初始化为0或未显式初始化的static局部变量. 栈 局部变量分配在栈上:函数调用传参过