我们都知道编程语言当中有变量这样的概念。我的理解是变量就是一种容器,它可以存储数据。那么这个变量存储什么样的格式的数据就是由变量类型来决定的了。
C语言当中,它的变量类型有如下几种:
注意:在学习数据类型主要从两个角度来思考,一是占用的宽度,也可以认为是占用的字节数。二是写入的数据格式。
整数类型的种类有char , short , int , long 。。。。这些类型的不同点在哪里呢?首先他们不同的种类对应的宽度不一样。简单说就是占用的字节数不一样。他们的格式是什么呢?我们来详细分析。注释:整数类型在二进制当中的存储格式为补码形式存储。
我们存储的数据都是以补码的形式存储(正数的补码与原码相同)。所以,我们用如下代码来查看一下。
运行之后,我们来看一下汇编语句以及在内存中查看一下存储的数据
现在我们知道了,无符号数的占用多少字节有数据格式决定。存储的方式有编码方式决定。
接下来,我们用下面的代码,来看看有符号数是如何存储的。
由反汇编代码,我们可以看到在有符号的数据类型当中,都是以补码的形式存储在内存当中。
常见的浮点类型的种类有float(4字节) , double(8字节) 。我们知道整数类型是采用的是补码的格式存储在主存当中的。浮点类型的存储方式就很不一样。我们来看看float 和double 这两个浮点类型是如何存储的。详细如下图:他是遵从IEEE编码规范的
首先,我们知道如何将十进制的浮点数如何转换成二进制表示。我们使用8.25来计算一下这个浮点数。我们先将9.25拆分开来,分为整数部分9,以及小数部分0.25。
整数部分转换为二进制: 9 = 1001
小数部分转换为二进制:0.25 = 01
接下来我们就知道了。十进制9.25转为二进制表示1001.01。那么我们将该表示方法转换为科学计数法即:1.00101 * 2e3 。接下来我们将数值对应放入Float 类型来看看。 它存入主存当中得二进制为0 10000010 00101000000000000000000 ,转换为十六进制为:41140000 (注释:其中指数部分填写运算,如果在转换科学计数法得时候小数点是向左边移动在指数部分最高位至1,如果小数点向右移动,则指数部分最高位至0,且余下部分由指数值-1得出新值在低位部分填充,比如文中案例,指数为3,即小数点向左移动,且3-1=2 换算成二进制为10。所以指数部分为10000010 )
上面,我们已经计算出来,接下来,我们设计一个代码,看看是不是正确的。
编译发现结果完全正确
数组是一种数据结构,简单的说他就是一段连续的变量。那么,我们有可能会听到什么int 类型的数组,这又是什么呢?我们来想想。还记得我们的数据类型嘛?有int 类型,占用4个字节。有Char类型,占用1个字节。那么什么类型的数组,本质上就是什么样的数据类型组成的连续的存储空间。我们用代码感受一下:
代码描述,该代码主要是定义了int , double,char类型的数组,且都在这两个数组当中预先存入的值。接下来我们编译一下,查看一下对应的汇编代码,我们发现,int 类型的数组元素存储的大小为dword,double类型的数组元素存储的大小为mmword,char类型的数组元素存储的大小为byte。
我们在跟踪一下内存看看。
我们仔细看看,在汇编代码当中,数组的元素表示是使用的EBP,我们直到EBP寄存器当中的值始终指向的是当前栈底部。所以,这么看起来他是在栈空间咯。前面我们直到,使用栈空间的函数预先一定会分配一定的缓冲区。我们由下图位置直到确实有划分缓冲区。
那么总结一下,所谓的数组,就是连续的不同类型的数组空间。
既然提到了数组,不免我们会联想到多维数组。那么多维数组的本质又是什么呢。同样我们用如下代码对比看看。
该代码同样是定义了一个一维数组,和多维数组。那么我们看看对应的汇编代码。
这个时候,我们由汇编代码来看,好像两者没有什么区别,一维数组age[10]通过EBP偏移来定位数组元素。多维数组age2[2][5]同样是如此。本质上好像没有什么区别。由此可见,无论是一维数组还是多维数组他的本质都是线性的连续存储在内存空间的。(即物理数据结构相同,逻辑结构不同)
现在我们了解了本质,那么问题来了。编译器是怎么能够做到分组并且定位的呢?比如?age2[1][3] 表示的是第二个分组的第3个元素。那他是怎么做到的呢?其实很简单。编译器只是使用了一个简单的算法。如:1*5+3。这样得出的结果就是下标为8的元素。
指针得概念通常是这么说的“存入地址得变量”我想了想,对也不全对。我得理解是:指针也是变量类型得一种,它和整数类型变量,浮点数类型变量是一样的,只是它有自己不同的类型属性罢了。其中“存入地址得变量”这个,我认为是这样的,编译器在处理指针类型当中存储的值的时候,会将它的值按照“地址”来处理。并非将地址放入指针当中。
下面我们详细的介绍一下指针类型。我们知道,指针类型是使用“*”配合常见的数据类型或者自定义的数据类型组合成为指针类型的,比如:int * 就是int类型的指针,double * 便是double类型的指针。
既然指针也是一种数据类型,那么同样我们也是需要从“长度”以及“数据格式”来学习。我们这里只是考虑一下长度问题,我们通过常见得使用方法,汇编状态下看看代码:
在“反汇编”窗口当中,我们发现对应的汇编代码。在基本类型当中,指针类型的长度为dword ,也就是4个字节。
了解指针的朋友,都知道,或者见过这样的一个写法“char ** a ”两个星号甚至多个星号等定义指针。我们用下面代码,来看看多*号指针的长度是多少。由验证得知,多星号的指针长度依然是4个字节。
接下来,我们用如下代码测试一下,多*号指针的类型是什么样子的。
运行完成之后,我们发现,代码报错,出现如下提示:
由此可见,多*号指针虽然同样是指针,但是星号的数目不同,他们就不是同一个指针类型。
运行结果如下:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-5-1 11:24
被天象独行编辑
,原因: