C语言的存储类

Auto  普通局部栈变量:是自动存储,限定变量只能在函数内部使用,这种对象会自动创建和销毁 ,建议这个变量要放在堆栈上面,调用函数时分配内存,函数结束时释放内存。一般隐藏auto默认为自动存储类别。我们程序都变量大多是自动变量。

实例 auto.c

1 #include <stdio.h>
2
3 int main(void)
4 {
5     auto int i = 9;  /* 声明局部变量的关键字是 auto; 因可以省略, 几乎没人使用 */
6     printf("%d\n", i);
7     getchar();  /*从缓冲区读走一个字符,相当于清除缓冲区*/
8     return 0;
9 }

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

实例 register.c

 1 #include <stdio.h>
 2 #include <time.h>
 3
 4 #define TIME 1000000000
 5 int m, n = TIME; /* 全局变量 */
 6
 7 int main(void)
 8 {
 9     time_t start, stop;
10     register int a, b = TIME; /* 寄存器变量 */
11     int x, y = TIME;          /* 一般变量   */
12
13     time(&start);
14     for (a = 0; a < b; a++);
15     time(&stop);
16     printf("寄存器变量用时: %ld 秒\n", stop - start);
17
18     time(&start);
19     for (x = 0; x < y; x++);
20     time(&stop);
21     printf("一般变量用时: %ld 秒\n", stop - start);
22
23     time(&start);
24     for (m = 0; m < n; m++);
25     time(&stop);
26     printf("全局变量用时: %ld 秒\n", stop - start);
27
28     return 0;
29 }

Static 静态变量(smtie):全局变量的默认存储类,表示变量在程序生命周期内可见;在 C 语言中,static 可以用来修饰局部变量,全局变量以及函数。在不同的情况下 static 的作用不尽相同。

(1)修饰局部变量

一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束。但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅限于该语句块。

在用static修饰局部变量后,该变量只在初次运行时进行初始化工作,且只进行一次。

 1 #include<stdio.h>
 2 void fun()
 3 {
 4     static int a = 1;
 5     a++;
 6     printf("%d\n", a);
 7 }
 8 int main(void)
 9 {
10     fun();
11     fun();
12     return 0;
13 }

程序执行结果为: 2 3

说明在第二次调用fun()函数时,a的值为2,并且没有进行初始化赋值,直接进行自增运算,所以得到的结果为3.

对于静态局部变量如果没有进行初始化的话,对于整形变量系统会自动对其赋值为0,对于字符数组,会自动赋值为‘\0‘.

(2)修饰全局变量

对于一个全局变量,它既可以在本源文件中被访问到,也可以在同一个工程的其它源文件中被访问(只需用extern进行声明即可)。

实例 file1.c

1 int a=1;

实例 file2.c

1 #include<stdio.h>
2 extern int a;
3 int main(void)
4 {
5     printf("%d\",a);
6     return 0;
7 } 

则执行结果为 1

但是如果在 file1.c 中把 int a=1 改为 static int a=1;

那么在file2.c是无法访问到变量a的。原因在于用static对全局变量进行修饰改变了其作用域的范围,由原来的整个工程可见变为本源文件可见。

(3)修饰函数

用static修饰函数的话,情况与修饰全局变量大同小异,就是改变了函数的作用域。

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

从作用域看:

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

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

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

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

从分配内存空间看:

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

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

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

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

Tips:

  • 若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
  • 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
  • 设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
  • 如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带"内部存储器"功能的的函数)
  • 函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

 

原文地址:https://www.cnblogs.com/zjx13123121231/p/8482364.html

时间: 2024-07-28 18:11:08

C语言的存储类的相关文章

4.7 C语言的存储类,作用域,生命周期,链接属性

C语言背后的运行机制,学会了会对C语言更加熟悉,可以直接看到C语言的骨头里去. 存储类(storage class): ①什么是存储类? 存储类就是变量存储类型,即变量在内存中存储在什么段. 例如:栈:普通局部变量. 数据段(.data):初始化不为零的全局变量,静态局部变量. bss段:初始化为零 或 未初始化的全局变量. (其实bss段就是初始化为0的数据段)   代码段(.text):存放程序执行代码的一块内存区域. ②存储类相关的关键字? auto static register ext

C语言之存储类的相关的关键字

不同的数据在内存中的存储位置是不同的,总体来说内存中存储数据的地方主要有四部分:栈.堆.数据段.bss段,这些地方分别存放着不同的数据,比如栈一般用来存储局部变量,堆内存需要程序员字自己申请以及释放,主要用来存放比较大的数据:数据段主要用来存放显示初始化的全局变量和static关键字修饰的静态局部变量:bss段一般用来存放未显式初始化的全局变量或显式初始化为0的全局变量(C语言中,默认全局变量初始化为0).C语言还提供了一些关键字来修饰变量,使其附有其他的属性,这些关键字主要有:auto.sta

C语言笔记之存储类

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

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

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

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

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

C语言学习系列(六)存储类

一.C存储类 存储类定义C程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在他们所修饰的类型之前.for example:auto.register.static.extern. (一).auto存储类 auto存储类是所有局部变量的默认存储类. { int mount; auto int month; } 上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量. (二).register存储类 register存储类用于定义存储在寄存器而不

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

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

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