滴水三期:day09.3-数据类型-基本类型

一、C语言数据类型

1.引入C语言数据类型

  • 汇编中的数据类型有byte、word、dword等
  • 那么C语言的数据类型除了有一个作用域的概念,其他的都和汇编的数据类型相似

2.学习数据类型的三要素

  • 存储数据的宽度:每种数据类型能容纳多大的数据
  • 存储数据的格式:虽然底层都是用0、1存储,但是使用不同数据类型时要注意里面存的数据到底是什么样的
  • 作用范围(作用域):哪里可以用、哪里不能用什么数据类型

3.C语言中的数据类型

  • 如下图所示:

    image-20211202210533372

二、整数类型

  • 整数类型:char、short、int、long

    char8bit1字节
    short16bit2字节
    int32bit4字节
    long32bit4字节
  • 那么和汇编的byte,word,dword有什么关系呢?我们举一个简单的例子来看一下

    void Func(){
    	char cTemp = 0xFF;
    	short sTemp = 0xFF;
    	int iTemp = 0xFF;
    }
    void main(int argc, char* argv[]) 
    {
    	Func();
    }
    
    image-20211203001429672

    如果你用char类型的变量来存储0xFF这个数据,那么汇编语言则会把0xFF这个数据存入内存中,且会用内存的8bit宽度来存储,所以可以看到是byte;而如果用short类型来存储0xFF,那么会用16bit宽度内存来存储,所以可以看到是word;同理如果使用int类型变量来存储0xFF,那么会用32bit宽度内存来存储,所以是dword

  • 所以从数据宽度来说:

    • 如果一个数据使用char类型变量存储,翻译成汇编则会用byte数据宽度内存来存储
    • 如果一个数据使用short类型变量存储,翻译成汇编则会用word数据宽度内存来存储
    • 如果一个数据使用int类型变量存储,翻译成汇编则会用dword数据宽度内存来存储
  • 如果存入数据的数据宽度大于数据类型宽度,还是和汇编一样,从低位开始向高位存储,存储规定的数据宽度,多余的高位数据舍弃

    void Func(){
    	char cTemp = 0x12345678;   //byte
    	short sTemp = 0x12345678;  //word
    	int iTemp = 0x12345678;    //dword
    }
    void main(int argc, char* argv[]) 
    {
    	Func();
    }
    
    image-20211203090908546

    第一个0x12345678是用char数据类型存储,即用byte数据宽度的内存存储,那么取低8位0x78存储到[ebp-4]

    image-20211203091217276

    第二个0x12345678是用short数据类型存储,即用word数据宽度的内存存储,取低16位0x5678存入[ebp-8]内存中,且是以字节为单位倒着存的,在0x0012FF24内存中存入78,在0x0012FF25内存中存入56。

    image-20211203092146041

    第三个0x12345678用int数据类型变量存储,即用dword数据宽度的内存存储,且数据从低位到高位倒着存储78存入0x12FF20,56存入0x12FF21,34存入0x12FF22,12存入0x12FF23(这里要注意和OD区分开,OD已经帮我们倒过来了,VC6++没有)

  • 整数类型分为有符号(signed)和无符号(unsigned)两种:

    • 但是在内存中存储的方式完全一样:计算机不管数据有无符号,它就只把数据化成二进制按照指定的数据宽度存在内存中

      image-20211203093908357 image-20211203093950918

    • 在做运算的时候需要注意有无符号的区别

      void Func(){
      	char x = 0xFF;
      	unsigned char y = 0xFF;
      	printf("%d",x);
      	printf("%d",y);
      }
      
      image-20211203095320125

      如果你定义0xFF为有符号数,那么计算机会翻译显示为-1;如果你定义0xFF为无符号数,则显示结果为255

    • 还有在比较的数据大小时,也要注意有无符号的区别:

      • 如果一个有符号和一个无符号数比较,那么最终汇编语言会使用有符号数比较的跳转指令JBE、JG等

        void Func(){
        	char x = 0xFF;
        	unsigned char y = 0xFF;
        	if(x>y){
        		printf("x>y");
        	}
        }
        
        image-20211203100627665

        movsx:带符号拓展后的mov指令,高位用符号位扩展

      • 如果两个有符号数比较,最终汇编语言会使用比较有符号数的跳转指令

        void Func(){
        	char x = 0xFF;
        	char y = 0xFF;
        	if(x>y){
        		printf("x>y");
        	}
        }
        
        image-20211203100849652
      • 如果两个无符号数比较,最终汇编语言会使用比较无符号数的跳转指令

        void Func(){
        	unsigned int x = 0xFFFF;
        	unsigned int y = 0xFF;
        	if(x>y){
        		printf("x>y");
        	}
        }
        
        image-20211203101707984

        注意:如果你用低于32位数据宽度的数据类型变量来存储,比较之前,汇编会自动帮你把数据扩展到32位,且是带符号扩展(movsx),所以最后比较的时候还是使用有符号数比较的跳转指令。现在为了防止这种情况的出现,直接用32位的容器存储数据即可。(后面会学习)

三、浮点类型

1.浮点类型

  • float和double
  • float数据类型宽度为32位;double数据类型宽度为64位

2.小数/浮点数在内存中存储方式

  • 十进制、十六进制等整数在可以转化成对应的二进制最终存入内存,但是小数无法像整数那样对样转化成二进制数,但是小数如果想存入内存,它也要想办法转成二进制,那么小数是如何存储的呢?

  • float和double在存储方式上都是遵从IEEE的规范的

    • float的存储方式:

      image-20211203111505165
    • double的存储方式:

      image-20211203111450602
  • 尾数部分宽度越长,表示小数的精确度越高,因为有些小数部分表示为二进制数是无限循环的,比如1.3。小数部分0.3用二进制表示:即不断的乘2:每次乘完2取整数部分作为二进制数,小数部分如果为0,则结束,如果不为0,则取出小数部分继续乘2。那么1.3表示为二进制为1.0100110 0100110 …无限循环下去,如果使用float存储,那么尾数部分精确到了23位;如果使用double存储,那么尾数部分就精确到了52位

3.将float类型转换为内存存储格式

下面海哥的方法个人认为不是很容易记忆,建议去b站看王道计算机组成原理的浮点数课程,讲解比较清晰

  1. 先将这个实数的绝对值化为二进制格式(不管正负,转换分为小数部分和整数部分)

    小数部分转换成二进制有一个精确位数的概念,因为可能出现无限循环的情况,所以要给定一个精确位数

  2. 将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字(1)的右边,此时结果为m

  3. 从小数点右边第一位开始数出二十三位数字放入第22到第0位(不够的用0补)

  4. 如果实数是正的,则在第31位放入“0”,否则放入“1”

  5. 如果m是小数点左移得到的,第30位放入“1”。如果m是小数点右移得到的或n=0,则第30位放入“0”

  6. 如果m是小数点左移得到的,则将n-1后化为二进制,并在左边加“0”补足七位,放入第29到第23位

    如果m是小数点右移得到的或n=0,则将-n-1化为二进制(补码)后,取低7位放入第29到第23位

  7. 接着将得到的32位每4位一组,化成十六进制方便我们表示

4.举例说明

  1. 8.25转换成浮点数存储

    • 整数部分8转换成二进制为:1000

      8/2   0   ↑  //不断的除以2,取余数
      4/2   0	  |
      2/2   0   |
      1/2   1   |
      
    • 小数部分0.25转换成二进制为:10

      0.25*2  0  |   //取小数部分不断的乘2,之后再取结果的整数部分
      0.5*2   1  ↓   //直到小数部分为0结束
      
    • 所以最终8.25用二进制表示为1000.10

  2. 小数点左移三位,小数点移到第一个有效数字的右边,接着用科学计数法表示:

    • 因为十进制数100.1可以表示为1.001*102。所以二进制1000.10移动后可以表示为:1.00010 * 23
  3. 从小数点右边第一位开始数出二十三位数字放入第22到第0位

    • 因为小数点右边开始为00010,所以将00010后面再补0,一共补充到总长度为22位即可

      image-20211203113545898
  4. 因为8.25是正数,则在第31位放入“0”

    image-20211203113644910
  5. 因为小数点当时是左移3位得到的1.00010 * 23,则在指数部分的首位即30位放入“1”

    image-20211203114015646
  6. 因为小数点是左移3位得到的1.00010 * 23,所以3-1=2化成二进制为10,接着在左边补0,补充到总长度为7即可

    image-20211203114412109

    另外一种方法:5和6可以用下面的方法代替:如果是左移n位得到的则指数部分为127+n化成二进制;如果是右移n位得到的则指数部分为127-n化成二进制(这里用到的是移码的知识,浮点数的存储方式可以看看王道计算机组成原理中的课程,在B站)

  7. 化成十六进制为:0x41080000

    0100 0001 0000 1000 0000 0000 0000 0000
    0x41080000
    

四、字符的存储

1.英文字符的存储

  • 可以这样存:char x = 'A';也可以这样存:char y = 65

    因为A对应的十进制ASCII码为65

  • ASCII编码:

    • ASCII 码使用指定的 7 位或 8 位二进制数组合来表示 128 或 256 种可能的字符

      • 标准 ASCII 码使用7 位二进制数来表示所有的大写和小写字母,数字 0 到 9、标点符号,以及在美式英语中使用的特殊控制字符(最高位,即第八位永远都是0)
      • 扩展 ASCII 码允许将每个字符的第8 位用于确定附加的128 个特殊符号字符、外来语字母和图形符号
    • 常用的字符对应的ASCII码为:

      二进制十进制十六进制字符
      0011 000048300
      0011 000149311
      0011 001050322
      0011 001151333
      0011 010052344
      0011 010153355
      0011 011054366
      0011 011155377
      0011 100056388
      0011 100157399
      0100 00016541A
      0100 00106642B
      0100 00116743C
      0100 01006844D
      0100 01016945E
      0100 01107046F
      0100 01117147G
      0100 10007248H
      0100 10017349I
      0100 1010744AJ
      0100 1011754BK
      0100 1100764CL
      0100 1101774DM
      0100 1110784EN
      0100 1111794FO
      0101 00008050P
      0101 00018151Q
      0101 00108252R
      0101 00118353S
      0101 01008454T
      0101 01018555U
      0101 01108656V
      0101 01118757W
      0101 10008858X
      0101 10018959Y
      0101 1010905AZ
      0110 00019761a
      0110 00109862b
      0110 00119963c
      0110 010010064d
      0110 010110165e
      0110 011010266f
      0110 011110367g
      0110 100010468h
      0110 100110569i
      0110 10101066Aj
      0110 10111076Bk
      0110 11001086Cl
      0110 11011096Dm
      0110 11101106En
      0110 11111116Fo
      0111 000011270p
      0111 000111371q
      0111 001011472r
      0111 001111573s
      0111 010011674t
      0111 010111775u
      0111 011011876v
      0111 011111977w
      0111 100012078x
      0111 100112179y
      0111 10101227Az

2.中文字符的存储

  • GB2312编码规则:

    • 天朝专家把那些127号之后的奇异符号们(即EASCII)取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了
  • **所以截取一个字符串的一段,如何区分是英文还是中文?**就看这个字节数值的范围,如果小于128就表示英文;如果大于则是汉字的两字节截取了一半(即看最高位为0还是1)

  • GB2312表:可以看到如果最终计算机存储的是0xB0A1,那么使用GB编码规则,这两个字节的值就表示这个汉字。但是注意:是计算机中存储的值为0xB0A1,而计算机内存中是按字节为单位倒着存的,强调过很多次了,所以我们实际上用的时候要写成0xA1B0

    image-20211204153017358

五、作业

  • 将float类型的12.5转换成16进制

    1. 将12.5用二进制表示:

      整数部分:
      	12 化成二进制-->   1100
      小数部分:
      	0.5 化成二进制-->   1
      	因为0.5*2=1.0    1
      综上12.5化成二进制为1100.1
      
    2. 小数点左移到第一个有效位的右边,此时用科学计数法表示为:1.1001*23。故左移了3位

    3. 将此时的小数位从21位依次存到0位,如果不够则补0

      image-20211204001032594
    4. 因为12.5是正数,所以31位为0

      image-20211204001922386
    5. 又因为小数部分是左移,所以30位为1

      image-20211204002028702
    6. 且因为小数二进制时左移3位得到的,所以3-1=2化成二进制为10,将10存入指数部分,不够的左边补0(或者因为3化成移码为3+127=130,130化成二进制即为10000010)

      image-20211204003104218
    7. 最后每四位一组化成十六进制为

      0100 0001 0100 1000 0000 0000 0000 0000
      0x41480000
      
    • 综上12.5转成十六进制为:0x41480000,存储在内存中为(倒着存入)00 00 48 41

    • 验证一下:

      image-20211204003246827
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值