变量存储机制

本文转载于:https://www.zhihu.com/question/34266997?from=profile_question_card程序员

问题:
      好比 int a = 5

      我知道有一块内存,存了这个值5,a表明了这块内存。就好像给一个盒子起名叫a,这个盒子里装了5,现实中这个名字,也就是a只是存在人脑里的,不是实话的。
另外a,b等字符在计算机里用很小的整数储存,也就是a和65对应。
    个人问题是 a = 5 的时候,有一块内存存了5,也就是这块内存是00000101,但计算机怎么知道这块内存叫a?这个名字a是在哪里储存的?
个人理解是否有一块专门存储变量名的内存,好比根据顺序第x块存了65,这个65又存了00000101的地址?但这样岂不是每一个变量都是指针?编程

解答:数组

  变量名不占空间数据结构

  变量:用来标识(identify)一块内存区域,这块区域的值通常是能够更改的,这就是它“变”的由来,可是咱们能够经过使用如const等一些修饰符号来限定这一内存区域的操做特性(characteristic),即变量的操做特性。用const修饰的使变量不能更改的就和常量同样的变量叫作常变量。
  变量名:是一个标识符(identifier),用来指代一块内存区域,即变量,使用变量使咱们操做内存以区域(area),以块(block)为单位,提升了方便性。
  你的机器代码中,是不会出现变量名的;变量名是给咱们程序员操做内存来使用的。
  想一想在汇编年代,没有变量名,咱们操做内存,都是用地址来直接操做的,还要控制区域大小;固然汇编语言已经有了简单的变量。
  对于编译器,它会搜集咱们的变量名,好比咱们定义了一个全局的int a;那么编译器都为咱们作了什么呢?
  它会为程序预留4个字节的空间(假设在32位平台),并把咱们的变量名“a”保存进符号表,并用这个符号表的索引对应实际的空间。
  若是下面出现b = a;那么它就会根据符号表找到变量的真正的物理位置,取得它的值,赋给b。
  这是写编译器须要作的,咱们须要创建符号表。
  可是实际在汇编层次上,操做的都是地址而已,不存在任何名称了。

  除了变量名不是内存地址,其余名都是地址。对么?ide

  所谓的其余名无非是函数名、标识符常量名、指针名、数组名、结构名、类名等等。
  好比指针名、数组名、函数名就是地址,它们分别表示指针所指向元素的地址、数组的首地址和函数的入口地址。
  变量名虽然不直接表示地址,但可用取地址符号&来得到它所表明的变量的存放地址。由于在定义变量的同时会分配给它相应的空间。
  但类和结构只有事例化时才为它分配空间,从而不能用取地址符号&来得到类名或结构名的地址。函数

  变量名是用来标识某个内存块的
  地址就是地址啦,如是变量名的话,用取地址运算符&就能够获得它标识的内存块的地址,
  而指针变量呢,它自己也是一个变量名,只不过它标识的那块内存存放的是一个地址值 工具

  变量是地址的别名..就像刚生的小孩,你只知道他在地球上的某个位置,而不能叫出他名字,给你取个名编码

  定义int a;时,编译器分配4个字节内存,并命名该4个字节的空间名字为a(即变量名),当用到变量名a时,就是在使用那4个字节的内存空间.
  5是一个常数,在程序编译时存放在代码的常量区存放着它的值(就是5),当执行a=5时,程序将5这个常量拷贝到a所在的4个字节空间中,就完成了赋值操做.

  a是咱们对那个整形变量的4个字节取的"名字",
是咱们人为给的,实际上计算机并不存储a这个名字,只是咱们编程时给那4个字节内存取个名字好用.实际上程序在编译时,全部的a都转换为了那个地址空间了.编译成机器代码后,没有a这个说法了.a这个名字只存在于咱们编写的代码中.
  5不是被随机分配的,而老是位于程序的数据段中,可能在不一样的机器上在数据段中的位置可能不一致,它的地址其实不能以咱们经常使用到的内存地址来理解,由于牵扯到一个叫"计算机寻址方式"的问题,因此写不少都解释不清楚,你本身找本汇编语言的书来学一下吧.........翻译

  C语言中变量只是标识对应存储单元内的存储内容。与地址的对应关系
  int a=3;
  a---&a一一对应啊,变量名只是一个便于记忆识别的名称,编译器会将他编译成相应的内存地址的.变量都要占据必定的内存。经过定义该变量的指针, [类型]* 指针名=你要指向的变量名那么该指针中存储的就是你的变量的内存地址。 &你的变量名 这样就能够直接获取到你的变量地址或者定义引用 [类型]& 引用名=变量名该引用可经过变量的地址来对变量进行修改.指针

~~~~~~~~~~~~~~~~~~~~~~~~~

  变量名是给编译器看的,编译器根据变量是局部仍是全局分配内存地址或栈空间,所谓的变量名在内存中不存在,操做时转换成地址数存放在寄存器中了。

  编译器会将合法的变量名放到一个叫“符号表”的一个表中。
  每一个符号对应一个地址。当你调用此变量时,就会根据此符号表找到对应的地址,而后进行操做。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  尚未运行怎么会占用内存呢?!(这一点还要怀疑吗!?)

  所谓在编译期间分配空间指的是静态分配空间(相对于用new动态申请空间),如全局变量或静态变量(包括一些复杂类型的常量),它们所须要的空间大小能够明确计算出来,而且不会再改变,所以它们能够直接存放在可执行文件的特定的节里(并且包含初始化的值),程序运行时也是直接将这个节加载到特定的段中,没必要在程序运行期间用额外的代码来产生这些变量。

  其实在运行期间再看“变量”这个概念就再也不具有编译期间那么多的属性了(诸如名称,类型,做用域,生存期等等),对应的只是一块内存(只有首址和大小),因此在运行期间动态申请的空间,是须要额外的代码维护,以确保不一样变量不会混用内存。好比写new表示有一块内存已经被占用了,其它变量就不能再用它了; 写delete表示这块内存自由了,能够被其它变量使用了。(一般咱们都是经过变量来使用内存的,就编码而言变量是给内存块起了个名字,用以区分彼此)

  内存申请和释放时机很重要,过早会丢失数据,过迟会耗费内存。特定状况下编译器能够帮咱们完成这项复杂的工做(增长额外的代码维护内存空间,实现申请和释放)。从这个意义上讲,局部自动变量也是由编译器负责分配空间的。进一步讲,内存管理用到了咱们经常挂在嘴边的堆和栈这两种数据结构。

  最后对于“编译器分配空间”这种不严谨的说法,你能够理解成编译期间它为你规划好了这些变量的内存使用方案,这个方案写到可执行文件里面了(该文件中包含若干并不是出自你大脑衍生的代码),直到程序运行时才真正拿出来执行!

 
 
解答二:

  我尝试从由底向上来解释题主的疑问,顺便推荐王爽的《汇编语言》,看了前几章题主应该就明白了,了解一点汇编,CPU工做原理和编译知识仍是有必要的

  1.机器语言
  机器语言是机器指令的集合。电子计算机的机器指令是-列二进制数字。计算机将之转变为一列高低电平,以使计算机的电子器件受到驱动,进行运算。
  如应用8086CPU 完成运算s=768+12288-1280,机器码以下:
  101100000000000000000011
  000001010000000000110000
  001011010000000000000101
  每行表明一个指令,我只是搬运工,反正看不懂,如今估计也找不到几个不靠工具看得懂这玩意的人了~
  [关于变量名]:机器语言中没有变量名的概念,一切操做都是直接对地址进行

  2.汇编语言
  早期的程序员们很快就发现了使用机器语言带来的麻烦,它是如此难于辨别和记忆,给整个产业的发展带来了障碍。因而汇编语言产生了。
  汇编语言与机器语言是每一个指令是一一对应的,最终由汇编器把写有汇编语言的文本文件编译成可执行程序。
  例如:将寄存器BX内的数据到AX中(寄存器是CPU内部的一组存储器,大多数指令都须要先将内存里的数据读入寄存器后才能开始运算。AX,BX是其中两个寄存器的代号)
  机器指令:1000100111011000
  汇编指令:mov ax,bx
  [关于变量名]:汇编语言中就有变量的概念。在编译时由汇编器计算相关变量的偏移或实际地址,在编译出的二进制机器语言中直接使用该地址操做内存。

   3.C语言
  程序员们后来发现,用汇编语言写程序仍是麻烦,由于它和机器指令意义对应,更加接近CPU的思惟,而不是人的思惟。因而发明了不少高级语言,C就是其中的一种。
C语言编译的过程,实际上首先经过 “编译器”将C语言翻译成汇编语言,再经过“汇编器”将汇编语言转化成机器代码,对于编译器来说,将C转化成汇编的时候,不是一一对应的关系,也就是说几行C代码,可能翻译成几十行汇编。而汇编语言指令和机器代码指令,从某种意义来说,是一个东西,二者是一一对应的关系。
[关于变量名]:C语言中到处是变量,即便是个指针,它自身也是个4字节的变量才能储存一个地址(32位程序)。编译后,有输出文件包括如下两种:
  1. 可执行文件(xxxx.exe),一段二进制文件,其中代码段(代码段,数据段啥的也能够百度了解)的机器指令CPU能够直接识别执行。
  2. 符号文件(xxxx.pdb),记录了变量和地址的对应信息。仅供调试使用,程序运行时不须要该文件。
  4.有了前面的介绍,我再来讲说题主的问题
  题主问变量名储存在哪儿,变量名储存的机制是什么?回答以下
  1. 程序运行时不须要知道某块内存对应的变量名,它只是按地址直接操做那块内存。
  2. C/C++编译器在编译时会计算出变量名对应的地址,在底层全部操做该变量的地方,都使用变量对应的地址参与运算。
  3. C/C++编译器还把变量名和地址对应的关系存在一个文件中的,这类文件叫符号文件。可是程序运行时不须要这些文件,没有这些文件程序同样能够正常工做。这些文件只是用来在调试时起做用的。看这份反汇编也就是利用机器语言和汇编语言指令一一对应的关系,把机器语言还原成汇编语言的结果。能够看到,寻址都是经过直接用地址,或则寄存器+偏移量等操做完成的,关于变量名的信息在二进制可执行文件里已经彻底没有了。若是在调试时想要恢复这些信息,就须要用到符号文件了。再看下面这份反汇编上图里有move eax,dword ptr [ebp-3C] 这样的指令, 而下图里有move eax,dword ptr [b]。也就是通过符号文件的帮助,在调试时能够把[ebp-3C]这样人看不懂的东西,还原成b这种人看得懂的变量名。在Windows下,符号文件的拓展名为pdb,通常xxxx.pdb这样的文件都是符号文件。若是要说计算机储存了变量名,在汇编/C/C++下应该指的就是这种了。再次强调程序运行时不须要知道某块内存对应的变量名,编译器已经将C语言翻译成二进制的机器语言,机器语言中没有变量名的概念,一切操做都是直接对地址进行,变量名只是保存在另外一个与运行无关的文件里供人调试时使用的。
  4. 固然上面是针对汇编/C/C++等编译语言说的。若是是Python等解释语言的话,其变量名和内存地址之类的信息解释器(解释器,编译器分不清楚自行百度)里是有相关记录的,具体是什么方式每研究过,Python能够参考《Python源码剖析》一书。
  5. 若是题主是想知道编译时a的地址是怎么肯定的,变量a及它的地址编译器是储存在一个什么数据结构里之类的话,能够好好看看编译原理,我没研究过
相关文章
相关标签/搜索