变量本质的认识

变量的本质

研究过程:

  1. 1.   程序1

对程序进行编译连接之后,生成.exe文件,再次用debug加载此程序,执行其汇编代码。

再次得到之前已经得到的结论,C语言中函数的参数传递是通过堆栈的方式进行参数传递的。

图1  堆栈传参

同时看出,函数的返回值保存在寄存器AX中,这也是之前得到过的结论。

同时发现,程序运行时,全局变量n的段地址在DS中,而且它具有一个特定的地址。

而对于局部变量a,b,我们发现它所代表的就是堆栈中的实参,也就是说,参数a,b的段地址在寄存器SS中。

而对于变量C而言,我们发现,汇编语言中用寄存器SI代替了C的功能。

函数的返回值一直在AX中保存。

接下来,做了这样的事情,在F2中定义了d,e,f三个变量,但是没有进行其他任何操作,结果发现对应的汇编代码中仍然是用SI来代替C变量,其他代码也不受影响,随即对d,e,f赋值,并做了一定的运算,发现变量d成了栈中的空间,变量e,f被SI,DI等效替代。而CX的作用则被AX取代。

从这里其实可以得出这样的结论了,局部变量只在被用的时候才会分配空间,而且对于局部变量,分配的空间有可能是堆栈段内存区,也有可能是寄存器,这取决于变量使用的频繁度和重要性。

而对于其释放,应该说,子程序调用结束后,但是在还未返回之前堆栈被释放,则以堆栈内存区作为空间的变量就被释放了,以寄存器作变量的从实际意义上讲,也被释放了,尽管里面的值未发生任何变化。

而对于参数,他的空间分配时机要早的多,在其他函数调用此调用函数的时候,也就是还没有进入子程序之前,参数的空间就被分配了,也就是堆栈区。对于其释放,则通过程序发现了一个现象:

图2  参数返回时机

通过程序可以清晰的看出,参数的释放是在子程序已经返回之后,即将执行下一条要执行指令之前,释放到了寄存器CX中。

通过程序,发现,f3返回时汇编指令使RETF而不是RET,也就是说f3本身是个远调用类型。

对于全局变量而言,通过在使用n相关的操作之前,对其进行printf()显示其段地址和偏移地址,发现能够正常显示,这说明,在

进入main函数之前,或者说,在需要用到n之前,它就已经被定义了,具有实实在在的物理地址。

  1. 2.   程序2

  关于静态变量和局部变量的区别研究

  程序结果显示为:

图3  静态变量和局部变量

从结果可以看出来,局部变量两次显示的结果一样,而静态变量a 却不同,通过程序1知道,局部变量在退出程序调用后,变量就被释放了,所以两次调用f函数显示的结果自然一样,而a的值是不同的可见,在结束第一个f函数调用的时候,变量a并未得到释放。观察汇编代码以了解其本质。

图4  静态变量汇编代码

可以发现的是,在未进入f函数之前,对静态变量的初始化却已经完成了,这是一个比较有趣的现象,推测其原因是在f函数的声明的时候系统预知要进行这样的处理。

总之,我们得到的一个结论是:静态变零不会再函数调用结束后释放,而且其声明和初始化在进入函数之前就完成了,而且其段地址在DS中,存储空间地址和全局变量似乎很类似。

那么问题是:静态变量和全局变量有什么区别,如何区分他们?

这个问题目前尚未找到一个好的解决方法。

  1. 3.   程序3

  对变量类型进行研究,所得汇编代码如下:

图5  数据类型所占空间

从汇编代码能够看出来,连续定义的变量其存储空间是连续的。无符号整型变量为一个字大小,无符号字符型为一个字节,无符号长整型为两个字空间。

  从汇编代码可以看出,对于字符型和普通整型无差别,但是对于长整型而言,inc指令变成了ADD指令,而且还要考虑进位情况。可见,数据类型对运算方式还是有差别的。其实从本质上思考这个问题,是因为8086CPU是16位的CPU,所以才会导致这个问题,如果是32位CPU的话,上面的运算方式应该是无差别的。

  1. 4.   程序4

  从源程序可以看出,struct stu 类型的变量a是一个全局变量,

struct stu 类型的变量b是一个局部变量。

图6  变量a的汇编代码

从其汇编代码中,我们可以得出基本结论:全局变量的段地址仍然放在了DS寄存器中,这一点是具有普遍规律的,全局变量仍然有一个固定的地址,局部变量仍然是通过堆栈的方式定义的。

而且承接程序三得出结论:连续定义的且属于同一类别(比如全局变量)的变量,他们在内存中地址是连续的。

  1. 5.   程序5

  这个程序的研究确实花费了比较长的时间不过确实发现了一些有趣的现象

  首先来说,这里再次强调前面已经得到的一般性规律:局部变量是放在了堆栈里面。

  现在研究如何返回结构体变量,

图7  结构体返回时的动作

   开始的时候读到这里的时候感觉莫名奇妙,不知道为什么会有这样奇怪的指令,后来重新看了一遍代码,并把栈空间以及它的地址给画了出来,再了解了LDS,LES指令的作用,突然想到这两条指令是串搬移的初始化操作,更巧的是DS:SI所指位置就是func函数中a.a变量值1的地址,而042E就是主函数中结构体变量a的值,而且发现cx为3,而下面的指令是字搬移指令,所以,我么得出结论:结构体变量返回是一种串操作!

通过下面的指令我们同时也发现,在像函数传递结构体的时候采用的也是同样的机制,即仍然是一种串操作!

未解决问题:

  1. 1.   全局变量和静态变量有什么区别,如何区分?
  2. 3.   汇编中为什么会出现远调用?

总结:

这个实验研究的比较广,几乎涉及到所有类型的变量,研究了所有的变量的存储位置,参数传递方式,申请和释放时机等,是我们深入学习C语言额基础。

时间: 2024-10-20 09:30:17

变量本质的认识的相关文章

C 提高1 内存四区 变量本质 栈开口方向 指针铁律1

C 提高第一天复习 内存四区,变量常量的本质,函数调用模型,栈开口方向,指针铁律1,指针是一种数据类型 C 提高学员标准:写一个标准的冒泡排序 选择法或者冒泡法排序 在一个函数内排序 通过函数调用的方式排序 数组做函数参数的技术盲点和推演 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int i = 0; int j = 0; int tmp = 0; int a[] = 

变量的本质

变量本质上就是代表一个"可操作的存储空间",空间位置是确定的,但是里面放置什么值不确定.我们可通过变量名来访问"对应的存储空间",从而操纵这个"存储空间"存储的值. Java是一种强类型语言,每个变量都必须声明其数据类型.变量的数据类型决定了变量占据存储空间的大小. 比如,int a=3; 表示a变量的空间大小为4个字节. 变量作为程序中最基本的存储单元,其要素包括变量名,变量类型和作用域.变量在使用前必须对其声明, 只有在变量声明以后,才能为其

24、2.4.1 变量的本质

变量本质上就是代表一个“可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定.我们可通过变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值. Java是一个强类型语言,每个变量必须声明其数据类型,变量的数据类型决定了变量占据存储空间的大小.比如,int a = 3; 表示a变量的空间大小为4个字节,字节(byte),一个字节为8位(bit),即1 byte = 8 bit. 变量作为程序中最基本的存储单元,其要素包括变量名,变量类型和作用域,变量在使用前必须对其进行声明,

深入理解数据类型、变量类型属性、内存四区和指针

数据类型可理解为创建变量的模具(模子):是固定内存大小的别名. 数据类型的作用:编译器预算对象(变量)分配的内存空间大小. 既能读又能写的内存对象,称为变量:若一旦初始化后不能修改的对象则称为常量. 变量本质:(一段连续)内存空间的别名. 内存四区 栈区(stack):也叫临时区,由编译器自动分配释放,存放函数的参数值,局部变量的值等. 堆区(heap):一般由程序员分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收. 全局区(静态区)(static):全局变量和静态变

iOS 成员变量,实例变量,属性变量的区别,联系

在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译器从GCC转换为LLVM(low leve

C++ 静态成员变量和静态成员函数

静态成员:在定义前面加了static 关键字的成员.如下: class CRectangle { public: CRectangle(); ~CRectangle(); static void PrintTotal(); private: int w, h; static int nTotalArea; static int nTotalNumber; }; CRectangle::CRectangle(int w_, int h_) { w = w_; h = h_; nTotalNumbe

C语言变量和变量属性

数据类型 数据类型可以理解为固定内存大小的别名. 数据类型是创建变量的模子. 1byte char 2byte short 4byte int 变量本质 变量是一段实际连续存储空间的别名. 程序中通过变量来申请并命名存储空间. 通过变量的名字可以使用存储空间. --------------------------------------------------------------- C语言中的变量可以有自己的属性. 在定义变量的时候可以加上 "属性" 关键字. "属性&q

辨析函数指针变量和指针型函数

在上一篇随笔(顺序表基本操作算法的代码实现)中,LocateElem()函数的第三个形参的形式是: Status (*compare)(Elemtype e,Elemtype temp); 这是一个函数指针变量,借此机会记录一下函数指针变量和指针型函数的区别. 一.写法上的区别 函数指针变量 指针型函数 int (*function)(int i); int  *function(int i){} 上面是一个例子,可看到函数指针变量只是在:*function处比指针型函数多了一对小括号,下面是两

【转截】iOS成员变量、实例变量、属性变量三者的联系与区别

一.类Class中的属性property 在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译