• 【C进阶】之存储类型及用户空间内部分布


    1 定义变量的格式

    存储类型 数据类型 变量名 = 初始值;

    2 6个存储类型

    自动存储区:auto register

    非自动存储区:const static extern volatile

    3 auto存储类型—>自动存储类型

    自动类型:局部变量属于自动类型,定义局部变量时,加auto或者不加auto都是一样的,一般省略auto.

    非自动类型:全局变量,使用static修饰的全局变量或者局部变量不可以使用auto进行修饰。

    #include 
    
    int s;  // 全局变量,属于非自动类型,不可以使用auto修饰
    // auto int k;  // error
    
    static int x; // 使用static修饰的静态全局变量,属于非自动类型,不可以使用auto修饰
    // auto static int x;   // error
    
    int main(int argc, const char *argv[])
    {
        /*your code*/
        int i;   // 自动类型变量,省略auto
        auto int j;  // 自动类型变量,使用auto修饰
    
        static int m;  //  使用static修饰的静态局部变量,属于非自动类型,不可以使用auto修饰
        // auto static int n;  // error
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4 register存储类型—>寄存器存储类型

    定义寄存器存储类型的变量,定义的变量分配一个寄存器的空间给变量使用。

    尽量不要定义寄存器类型的变量,在CPU中寄存器的数量有限(空间有限)

    寄存器变量不可以进行去地址取运算(&),原因是寄存器没有地址。

    5 const存储类型—>常量存储类型

    1.只读,初始化后不能修改;

    2.使代码更紧凑;

    3.编译器自然保护不希望改变的参数,防止无意修改代码

    (例:const int * p=&a ,表示*p不能改变a的值

    ​ int const * p=&a ,表示*p不能改变a的值

    ​ int * const p=&a ,表示p指向的地址不能改变

    ​ const int * const p=&a ,表示既不能改变指向的地址,又不能改变指向地址中的值)

    6 static —>静态存储类型

    1.static修饰局部变量:延长生命周期到整个进程结束,

    ​ 只在第一次调用此函数时,对静态局部变量进行初始化,后面在此调用函数,不在初始化

    ​ 如果定义的静态局部变量没有进行初始化,默认初始化为0

    2.static修饰全局变量:外部文件不可以使用,静态全局变量的作用域在本文件内。

    3.static修饰函数:外部文件不可以使用,静态全局变量的作用域在本文件内。

    7 extern—>修饰全局变量

    1.externa修饰全局变量,表示这个全局变量在其他文件中定义的

    2.externa修饰函数,表示这个函数是在其他文件中定义的

    3.声明一个变量,extern声明的变量没有建立存储空间。int a;//变量在定义的时候创建存储空间

    8 volatile—>易变存储类型

    volatile关键字用来阻止编译器认为的无法“被代码本身”改变的代码进行优化。

    如在C语言中,volatile关键字可以用来提醒编译器它后面所定义的变量随时有可能改变,

    因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。

    如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,

    如果这个变量由别的程序更新了的话,将出现不一致的现象。

    在java并发编程中,volatile的作用

    对于可见性,java提供了volatile关键字来保证可见性。

    当一个共享的变量被volatile修饰时,它会保证修改的值会立即被更新到主存当中,当其他线程需要读取时,

    它会去内存中读取新值。

    9 用户空间内部分布图

    在这里插入图片描述
    在这里插入图片描述

    代码解析:

    #include 
    
    int d; // 全局变量未初始化 值为0 .bss
    int e=10; //全局变量初始化 .data
    char *p = "hello"; //字符指针 p在.data "hello"在.rodata
    char arr[] = "world"; //.字符数组 .data
    static int f; //使用static修饰的未初始化的全局变量 值为0 .bss
    static int g=20; //使用static修饰的初始化的全局变量 .data
    
    int main(int argc, const char *argv[])
    {
         int a=10; //局部变量初始化 栈区
         int b; //局部变量未初始化,随机值 栈区
         static int c; //使用static修饰的局部变量 未初始化 值为0 .bss
         static int d=20; //使用static修饰的局部变量初始化  .data
         char *p = "hello"; //字符指针 p:在栈区 “hello”在 .rodata
         char arr[] = "world"; //字符数组 栈
         char *q = malloc(10); //q在栈区,指向堆区的10字节的⾸地址
         return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    主成分分析的基本原理
    Docker基本使用和认识
    人工智能:支持向量机SVM 练习题(带解析)
    算法竞赛进阶指南0x35高斯消元与线性空间
    TypeError: %c requires int or char
    多测师肖sir_高级金牌讲师_python之作业006
    java+mysql基于SSM共享型汽车租赁系统-计算机毕业设计
    低代码与国产化部署:软件开发的未来趋势与应用实践
    React - 路由组件传参
    基于非链式(数组)结点结构的二叉树的前(先)序输入创建以及遍历
  • 原文地址:https://blog.csdn.net/distant_Rove666/article/details/127608500