zoukankan      html  css  js  c++  java
  • C语言里面变量和变量名的存储(转)

    转自:https://blog.csdn.net/weixin_33724659/article/details/88028054

    为了说明这个问题,咱们简单的来说一下C里面变量在内存里面的存储:

    1.栈区(stack)— 由编译器自动分配释放 ,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

    2.堆区(heap) — 一般由程序员分配释放, 用来存储数组,结构体,对象等。若程序员不释放,程序结束时可能由OS回收。

    3.全局区(静态区)(static)— 存放全局变量、静态数据、常量。程序结束后由系统释放。

    4.文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放。

    5.程序代码区 — 存放函数体(类成员函数和全局函数)的二进制代码。

    栈内存是有大小限制的,比如默认情况下,Linux平台的是8MB,如果超过这个限制,就会出现 stackoverflow,而堆内存并无限制,内存有多大就可以申请多大。

    看完上面的说明,我们可以得出一个结论: 全局变量存放在全局区,在程序一开始就分配好了,而且局部变量在存放在栈区,运行的时候分配内存,用完之后内存会被自动释放。

    但是这好像并没有说明变量名在哪里吧?比如下面这段C代码,a, b到底存在哪里?:

     1 #include <stdio.h>
     2  
     3 int a = 1;  //全局初始化区
     4  
     5 int main(int argc, char const *argv[])
     6 {
     7     int b;    //
     8     b = a + 5;
     9     printf("%d
    ", b);
    10     return 0;
    11 }

    为了搞明白这个问题,我们需要了解一下C语言的执行过程,C语言执行需要经过预处理(Preprocessing)、编译(Compilation)、汇编(Assemble)、链接(Linking)等几个阶段,在编译成汇编语言这个阶段就已经没有变量名了,使用gdb可以查看编译后的汇编代码:

       (gdb) disass main
    Dump of assembler code for function main:
       0x0000000000400526 <+0>:    push   %rbp
       0x0000000000400527 <+1>:    mov    %rsp,%rbp
       0x000000000040052a <+4>:    sub    $0x20,%rsp
       0x000000000040052e <+8>:    mov    %edi,-0x14(%rbp)
       0x0000000000400531 <+11>:    mov    %rsi,-0x20(%rbp)
       0x0000000000400535 <+15>:    mov    0x200afd(%rip),%eax        # 0x601038 <a>
       0x000000000040053b <+21>:    add    $0x5,%eax
       0x000000000040053e <+24>:    mov    %eax,-0x4(%rbp)
       0x0000000000400541 <+27>:    mov    -0x4(%rbp),%eax
       0x0000000000400544 <+30>:    mov    %eax,%esi
       0x0000000000400546 <+32>:    mov    $0x4005e4,%edi
       0x000000000040054b <+37>:    mov    $0x0,%eax
       0x0000000000400550 <+42>:    callq  0x400400 <printf@plt>
    => 0x0000000000400555 <+47>:    mov    $0x0,%eax
       0x000000000040055a <+52>:    leaveq 
       0x000000000040055b <+53>:    retq   
    End of assembler dump.

    虽然上面这个很难读懂,但是应该能看到在这一大堆汇编指令执行的背后,并没有变量名这个东西,所有的变量名到最后都变成了内存地址,汇编指令操作的是各种寄存器和内存地址。

    定义int a;时,编译器分配4个字节内存,并命名该4个字节的空间名字为a(即变量名),当用到变量名a时,就是在使用那4个字节的内存空间。 5是一个常数,在程序编译时存放在代码的常量区存放着它的值(就是5),当执行a=5时,程序将5这个常量拷贝到a所在的4个字节空间中,就完成了赋值操作.a是我们对那个整形变量的4个字节取的"名字",是我们人为给的,实际上计算机并不存储a这个名字,只是我们编程时给那4个字节内存取个名字好用。实际上程序在编译时,所有的a都转换为了那个地址空间了,编译成机器代码后,没有a这个说法了。a这个名字只存在于我们编写的代码中.5不是被随机分配的,而总是位于程序的数据段中,可能在不同的机器上在数据段中的位置可能不一致,它的地址其实不能以我们常用到的内存地址来理解,因为牵扯到一个叫"计算机寻址方式"的问题。

    以上的内容有参考网上很多文章,仅供参考!有一点需要明白在操作系统里面,程序的内存地址并不是物理地址,而且通过一个基址+偏移量的方式的计算得到的虚拟地址,操作系统为了更好的管理应用在内存这个层面做了很多抽象。

  • 相关阅读:
    Tensorflow和pytorch安装(windows安装)
    KNN和K-Means算法
    numpy 介绍与使用
    opencv简单实用(cv2)
    使用matplotlib画图
    python图片处理PIL
    webpack
    Vue路由(vue-router)
    Vue组件
    Vue过滤器、生命周期函数和vue-resource
  • 原文地址:https://www.cnblogs.com/y4247464/p/12573434.html
Copyright © 2011-2022 走看看