变量的四大存储类型static extern auto register

这篇具有很好参考价值的文章主要介绍了变量的四大存储类型static extern auto register。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 在C语言中变量和函数有数据类型和存储类型两个属性,因此变量定义的一般形式为:存储类型 数据类型 变量名表;

C语言提供了一下几种不同的存储类型:

(1) 自动变量(auto)

(2) 静态变量(static)

(3) 外部变量(extern)

(4) 寄存器变量(register)

下面一个一个介绍:


 

外部变量(全局变量)extern----全局静态存储区

定义 引用性声明

标准定义格式:extern 类型名 变量名;

如果在所有函数之外定义的变量没有指定其存储类别,那么它就是一个外部变量,它的作用域是从它的定义点到本文件的末尾在单个源文件中的确是这样,如果有多个源文件,全局变量的作用范围不是从变量定义处到该文件结尾,而是在其他文件中也有效)但是如果要在定义点之前或者其他文件中使用它,那么就需要使用关键字extern对其进行声明(注意不是定义,编译器并不为其分配内存)

  • 总结说也就是,函数之外没有指定存储类别的,一般是外部变量,作用域是定义位置到文件末尾。但是要在其他文件中使用需要extern声明,不分配内存。

举例说明:

具体实现步骤如下:

在 file1.c 文件中定义全局变量 count:int count = 0;

在 file2.c 文件中使用 extern 声明 count 变量:extern int count;

这样,在 file2.c 文件中就可以访问 count 变量了,而不需要重新定义它。在编译时,两个源文件将被链接起来,共享同一个 count 变量。


 

注意:extern int i 是声明,但是初始化赋值就是定义了。

extern int i; //是声明,不是定义,没有分配内存
int i; //是定义

如果在声明的时候给变量赋值,那么就和去掉extern直接定义变量赋值是等价的

extern int a = 10;//尽量不要写这种定义方式
int a = 10;//上述两条语句等价

尽量不要这样写,这样就分配内存空间了


 

❗易错点:函数之外未定义的变量一般是外部变量 extern

也就是说一般没指定存储类别的变量咱们常见的是extern定义的,也就是说 全局变量是声明,局部变量(函数变量)是定义! ,区别在于占用空间。

举例如下:

//说一般没指定存储类别的变量咱们常见的是extern定义的,也就是说 **`全局变量是声明,局部变量(函数变量)是定义!`** ,区别在于占用空间。
#include<stdio.h>

//全局变量
int a;
int a;  //函数外边,相当于extern声明??  ,声明可以??????

int main()
{
    int b;
    int b;  //函数内部,相当于局部变量。相当于auto int b;定义只能一次。会报错
   return 0;
}

 

全局变量 与 局部变量的区别

Tips:
定义:表示创建变量或分配存储单元
声明:说明变量的性质,但并不分配存储单元

extern int i; //是声明,不是定义,没有分配内存
int i; //是定义

如果在声明的时候给变量赋值,那么就和去掉extern直接定义变量赋值是等价的

extern int a = 10;//尽量不要写这种定义方式
int a = 10;//上述两条语句等价

(注意上面的不同语句对声明和定义的区分,对源文件中的局部变量来说是成立的(也就是.c文件),而对于源文件中的全局变量(外部变量)int a和在头文件中的int a就不能用上面的语句来解释声明和定义的区别)

补充:定义和声明的一个小坑,对于int a;来说,在源文件中,如果是全局变量的话就是声明,如果是局部变量的话就是定义


 

‼️ 谨记:声明可以多次,定义只能一次


 

extern的生存周期

extern 关键字只是声明一个变量,它并不会直接创建变量的实体,因此没有生命周期的概念。

具体来说,extern 只是向编译器声明某个变量已经在别处定义过,让编译器在编译时知道这个变量的存在。这样,在链接阶段,编译器就能够将所有用到该变量的代码与它的定义进行链接,从而使得程序能够正常运行。

因此,extern 声明的变量的生命周期与其定义的实体的生命周期是一致的,即它们都是在程序运行期间一直存在的。这意味着,如果一个全局变量在某个文件中被定义为 extern,那么它的生命周期将与整个程序的生命周期相同,只要程序运行,该变量就一直存在。


 

静态存储类— static

定义

  • 在 C 语言中,可以使用 static 关键字来定义静态存储类变量或函数。

对于静态存储类变量,static 关键字用于改变变量的存储位置和作用域。具体来说,使用 static 定义的变量存储在静态存储区中,具有静态持续性,即使函数返回,它的值也会保留。而且,static 变量只能在当前文件中访问,不能被其他文件访问。

  • 定义格式:static 类型符 变量名称 = 初始值;

举例:

#include <stdio.h>

void func(void);


static int count = 10; // 定义静态存储类变量

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

在上面的代码中,count 和 i 都是静态存储类变量,它们的值在函数调用之间保持不变。同时,count 只能在当前文件中访问,而 i 只能在 func() 函数中访问。

 

❗易错点:static 变量的值只会在第一次初始化时被赋值,之后在函数调用之间保持不变。

举例说明:

#include <stdio.h>

void func(void);

int main()
{
    for (int i = 0; i < 5; i++)
    {
        func();
    }
    return 0;
}

void func(void)
{
    static int i = 5; // 定义静态存储类变量 static
    int j = 5; // 定义自动存储类变量 auto 

    i++; // 对静态变量进行自增
    j++; // 对自动变量进行自增

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

在上面的示例中, func() 函数中定义了一个静态变量 i 和一个自动变量 j。在 func() 函数的每次调用中,i 的值都会自增1,而j 的值则会在每次调用中被初始化为5,然后自增1。

运行程序,执行效果如下:

i is 6 and j is 6
i is 7 and j is 6
i is 8 and j is 6
i is 9 and j is 6
i is 10 and j is 6

可以看到,static 变量 i 的值在函数调用之间保持不变,并且在每次调用时自增1,而自动变量 j 的值在每次调用时都会被重新初始化为5,然后自增1。

这说明了 static 变量的值不会改变的原因是因为它们具有静态存储期和静态链接性。


如果定义为全局静态变量也不会变,还是会保持值,不会被初始化。

#include <stdio.h>

void func(void);
static int i = 5; // 定义静态存储类变量 static
int main()
{
    for (int i = 0; i < 5; i++)
    {
        func();
    }
    return 0;
}

void func(void)
{
    
    int j = 5; // 定义自动存储类变量 auto 

    i++; // 对静态变量进行自增
    j++; // 对自动变量进行自增

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


不会变化的具体原因是:

static 定义的变量值不会变化的具体原因是因为:

  1. 静态存储期:static 变量被分配在静态存储区中,该区域的变量在程序运行期间一直存在,而不是像局部变量一样在函数调用结束后销毁。
  2. 静态链接性:static 变量具有静态链接性,只能被定义它的源文件内的函数访问,其他文件无法访问。
  3. 变量只被初始化一次:static 变量只被初始化一次,在其它时刻,只是在其原有的基础上进行修改。因此,变量的值在函数调用之间保持不变。

综上所述,static 变量值不会改变的原因是因为它们具有 静态存储期和静态链接性,以及变量只被初始化一次,所以在函数调用之间保持不变。


这个易错点很重要,也是static的特别之处。特点。


 

static的生存周期— 取决于程序运行周期,不仅仅在函数调用期间

static 定义的变量有静态存储期,意味着它们在程序运行期间一直存在,直到程序结束才被销毁。在函数内部,static 定义的变量只会被初始化一次,在其它时刻,只是在其原有的基础上进行修改,因此其值在函数调用之间保持不变。

具体来说,static 定义的变量的生存周期取决于其定义位置如果在函数内部定义了 static 变量,则该变量的生存周期为整个程序的运行期间,而不是仅在函数调用期间。

举例:

#include <stdio.h>

void test()
{
    static int i = 0;
    printf("i = %d\n", i);
    i++;
}

int main()
{
    for (int j = 0; j < 3; j++)
    {
        test();
    }
    return 0;
}

在这个示例中,test() 函数内部定义了一个 static 变量 i,并在每次调用 test() 函数时输出 i 的值。由于 i 是 static 变量,所以它的值在函数调用之间保持不变,并且在每次调用时自增1。

运行程序如下:

i = 0
i = 1
i = 2

可以看到,i 的值在函数调用之间保持不变,每次调用时自增1,这说明了 static 变量的生存周期是整个程序的运行期间,而不是仅在函数调用期间。


 

下面总结下区别 : 对比记忆

extern与static的作用域和周期的不同

extern 和 static 是 C 语言中的两个关键字,它们在变量的作用域和生命周期上有很大的不同。

作用域:

  • extern 关键字用于声明外部变量,也就是在一个源文件中定义,而在另一个源文件中声明。外部变量具有全局作用域,也就是说,它们的作用域不限于定义它们的函数或代码块。

  • static 关键字用于定义静态变量,静态变量的作用域仅限于定义它们的函数或代码块,也就是说,它们只能在其定义的代码块中访问。

周期:

  • extern 关键字用于声明外部变量,其定义和初始化在另一个源文件中进行。因此,外部变量的生命周期和作用域是整个程序的运行期间,也就是说,它们在程序开始时创建,在程序结束时销毁。

  • static 关键字用于定义静态变量,静态变量的生命周期是整个程序的运行期间。在函数内部定义 static 变量,这个变量只会被初始化一次,然后在函数调用之间保持不变。

综上所述,extern 和 static 关键字定义的变量的作用域和生命周期都有所不同,需要根据具体的需求来选择使用哪个关键字来定义变量。


因此,你可以这样理解:

  • extern 关键字声明的变量可以在整个程序中访问,它的生命周期和作用域是全局的,直到程序结束时被销毁。

  • static 关键字定义的变量只能在同一个源文件中访问,它的生命周期是整个程序的运行期间,但作用域是局部的,只能在定义它的函数或代码块中访问,直到程序结束时被销毁。

  • 还有个不同之处是 extern是声明,static是定义。 这取决于extern的特殊性

 


auto 自动存储类别— 默认 — 动态存储

在 C 语言中,auto 存储类型是默认的存储类型,如果没有显式地指定存储类型,则变量会被默认为自动存储类型。

举例:在函数内部定义一个自动变量:

void myFunction() {
    auto int x = 0;
    // ...
}

自动存储类型的变量会在定义它的函数或代码块中被创建,当函数或代码块执行完毕时,自动存储类型的变量也会被销毁。这意味着,变量的生命周期仅限于它所在的函数或代码块内部,不能被其他函数或代码块访问。

在上述代码中,变量 x 被定义为自动存储类型。它的作用域和生命周期仅限于函数 myFunction() 中,在函数执行完毕后会被销毁。

  • 需要注意的是,在 C 语言中,使用 auto 声明变量时,不能同时给出变量的存储类别说明符,例如不能将 auto 与 static 或 extern 同时使用,因为这样会产生二义性。

  • 不赋初值的话,随机值

  • 不专门声明为 static 存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。

  • 关键字 auto 可以省略,auto 不写则隐含定为“自动存储类别”,属于动态存储方式


 

register—— 寄存器存储

register 是 C 语言中的一种存储类别(Storage Class),它用于告诉编译器将变量存储在寄存器中。在 C 语言中,变量的存储位置可以是寄存器、堆栈或静态存储区,使用 register 存储类别可以帮助我们优化代码性能,因为寄存器访问速度比访问内存快。

存储在内存中 CPU寄存器

在 C 语言中,使用 register 关键字声明变量时,它将被存储在 CPU 的寄存器中,而不是存储在内存中。由于寄存器是 CPU 内部的高速存储器,所以变量的访问速度会更快,从而提高程序的执行效率。但需要注意的是,变量的存储位置和寄存器的数量都是由编译器决定的,使用 register 关键字只是向编译器建议将变量存储在寄存器中,但并不保证一定会存储在寄存器中。

需要注意的是,由于寄存器的数量是有限的,所以并不是所有的变量都可以存储在寄存器中。编译器会根据实际情况和编译器选项来决定哪些变量应该存储在寄存器中。因此,使用 register 关键字并不一定会提高程序的性能,有时可能会适得其反。建议只在必要时使用 register 关键字,或者让编译器自动决定变量的存储位置。

举例:例如,在函数内部定义一个 register 变量:

void myFunction() {
    register int x = 0;
    // ...
}

在上述代码中,变量 x 被定义为 register 存储类型,它将被存储在寄存器中(如果编译器允许的话)。由于寄存器的访问速度比内存快,因此访问变量 x 的速度会更快,从而提高程序的性能。


‼️重点:register 的注意事项

  1. 用register修饰的变量只能是局部变量和函数参数,不能是全局变量和静态变量。因为cpu的资源有限,因此不可能一直让一个变量一直占着cpu寄存器

  2. register变量一定是cpu可以接受的值

  3. 不可以用&运算符对register变量进行取址 使用 register 存储类别的变量不能直接获取其内存地址,因为它们可能存储在寄存器中,而寄存器没有地址。 使用 register 存储类别的变量不要取地址,因为这样会导致编译器无法将其存储在寄存器中,从而影响程序的执行效率。

  4. register只是请求寄存器变量,不一定会成功。

总之,使用 register 存储类别应该根据具体的应用场景进行考虑,避免过度使用 register 存储类别,从而影响程序的性能。


 

用于单片机的道理——提高效率

register 存储类别在单片机编程中也经常被使用。由于单片机资源有限,使用寄存器存储变量可以节约存储空间,提高程序执行效率。特别是在需要频繁访问变量的场景下,使用 register 存储类别可以提高程序的响应速度。

举例来说,如果需要在单片机中使用计时器,可以定义一个 register 变量来存储计时器的值。这样,在每次需要使用计时器时,就可以直接访问寄存器中的值,而不需要从内存中读取,从而提高程序的执行效率。

需要注意的是,在单片机编程中使用 register 存储类别需要谨慎,因为寄存器的数量很少,而且需要编译器支持。过度使用 register 存储类别可能会导致编译器无法将变量存储在寄存器中,从而影响程序的性能。因此,需要在具体应用场景下根据实际情况决定是否使用 register 存储类别。


 

总结:四种存储类别对比

下表对 C 语言中的四种存储类别进行了比较,包括了生存周期、作用域、存储方式、存储区域等方面:

存储类别 生命周期 作用域 存储方式 存储区域 使用场景
auto 函数内部 块级别 RAM 用于存储局部变量
static 整个程序 块级别 数据段 RAM 用于存储局部变量的持久性版本
extern 整个程序 文件级 数据段 RAM 用于在不同的源文件中共享全局变量
register 函数内部 块级别 寄存器 CPU 用于提高变量的访问速度

其中,“存储方式”指的是变量在内存中的存储方式,包括栈、堆、数据段和寄存器等;“存储区域”指的是变量在程序执行期间所占用的存储区域,包括 RAM 和 CPU 寄存器等。文章来源地址https://www.toymoban.com/news/detail-758366.html


到了这里,关于变量的四大存储类型static extern auto register的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++中static静态成员变量和静态成员函数、explcit和隐式类型转换、友元函数()详解

    声明为 static 的类成员 称为 类的静态成员 ,用 static 修饰的 成员变量 ,称之为 静态成员变量 ;用 static 修饰 的 成员函数 ,称之为 静态成员函数 。 静态成员变量一定要在类外进行初始化   静态成员 为 所有类对象所共享 ,不属于某个具体的对象,存放在静态区   静态成

    2024年02月04日
    浏览(45)
  • static、extern、inline 说明符和链接属性

    在我初学 C++ 时, static 、 inline 、 extern 可能是最令我迷惑的 C++ 说明符,原因是它们在不同的语境下会发挥不同的作用,而且某些说明符的含义已经和以前不同,这加剧了我在查询资料时的困扰。所以今天决定好好总结一下。 首先要介绍 C++ 的两个概念: 存储期 和 链接 。

    2024年02月05日
    浏览(70)
  • extern static 在linux 和 qt下差别

     从五个点来说 1.p3.h 中 静态定义一个const的int 变量并且赋值 2.p5.h 声明函数test2的定义 3. 直接extern 引用声明 test1() 函数 而不是像p5.h一样 把函数声明写到头文件 在别的.c文件直接包含头文件  第二点和第三点 是引用声明函数的两种用法 4.main函数 中static静态定义一个const变量

    2024年01月20日
    浏览(35)
  • extern\const\static的使用详解

    1.extern 利用extern,可以在一个文件中引用另一个文件中定义的变量或者函数, extern  可以应用于全局变量、函数或模板声明。   extern  具有四种含义,具体取决于上下文: 在非  const  全局变量声明中, extern  指定变量或函数在另一个转换单元中定义。 必须在

    2024年02月01日
    浏览(25)
  • 变量的存储类型(全局,局部,静态,动态)

    存储类型 是指变在内存中的存储方式,有静态存储和动态存储方式。 1.静态存储方式 静态存储方式的变量存储在内存的静态区,在程序编译时就已经分配好了内存空间。在整个程序运行时,该变量一直占有固有的内存空间,程序结束后才释放该部分内存空间。其中静态局部

    2024年02月03日
    浏览(35)
  • 《C和指针》笔记12: 存储类型(自动变量、静态变量和寄存器变量)

    在 代码块内部声明的变量 的缺省存储类型是自动的(automatic),也就是说它存储于堆栈中,称为自动(auto)变量 。auto就是用于修饰这种存储类型的,但它极少使用,因为代码块中的变量在缺省情况下就是自动变量。 在程序执行到声明自动变量的代码块时,自动变量才被创

    2024年02月10日
    浏览(37)
  • C++声明extern变量和extern函数的用法

    目录  一、 声明extern变量 1、 如何声明 2、在何处声明 3、在何处初始化 4、在何处调用 5、举例声明extern变量 (1)、声明extern变量的test.h文件 (2)、初始化extern变量的test.cpp文件 (3)、调用extern变量的main.cpp文件 二、声明extern函数 1、 如何声明 2、在何处声明 3、在何处定

    2024年02月15日
    浏览(37)
  • c++全局变量extern

    extern 是 C++ 中的一个,用于声明一个变量或函数是在其他文件中定义的。它的作用是告诉编译器在链接时在其他文件中寻找该变量或函数的定义。 在 C++ 中,如果一个变量或函数在多个文件中使用,那么就需要在每个文件中都声明一次该变量或函数。这时就可以使用

    2024年02月08日
    浏览(40)
  • 使用C语言自定义头文件,声明的变量或者函数用extern和不同extern修饰有什么区别?

    在C语言中,当在头文件中声明变量或函数时,使用 extern 和不使用 extern 修饰有以下区别: 使用 extern 修饰变量: extern 修饰的变量只是声明,不分配存储空间。它表示该变量的定义在其他源文件中,需要在使用该变量的源文件中进行定义和分配存储空间。 不使用 extern 修饰的

    2024年02月10日
    浏览(44)
  • 是否可以在static环境中访问非static变量,用代码说明

    在静态环境中无法直接访问非静态(非static)变量。静态环境指的是静态方法或静态代码块,它们在类加载时执行,并且不依赖于对象的实例。非静态变量是实例变量,它们的值是与类的每个实例对象相关联的。 下面是一个示例代码,展示了在静态方法中访问非静态变量会导

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包