整型数据的存储与读取

    数据在计算机中是以二进制补码的形式储存的。不同的数据类型有不同的补码形式。下面分别就数据类型和数据的存放、读取讨论。

一.数据的类型
数据类型分为原生数据类型和自定义数据类型。
(1)原生数据类型(内置类型):包括我们常用的int、char、short、long、float、double.
说明:整型家族有char、int、long、short,它们又分为有符号类型(signed)和无符号类型(unsigned).其中,char类型 的数据占1个字节,int类型的数据占4个字节,short类型的数据占2个字节,long类型的数据占8个字节。
(2)自定义数据类型:包括结构体类型(struct)、联合体类型(union)、枚举类型(enum)等。
数据类型的意义:定义一个变量,我们通常要说明它的类型。而在定义一个变量时,内存就为它开辟一个空间。那么,内存是怎么开辟空间的呢?没错,这就要发挥类型的作用了。所以,类型决定了内存开辟空间的大小,还决定了使用的空间。此外,在之后对数据的操作中,我们总要结合数据的类型而参考对数据的操作,所以,类型还决定了我们如何看待所开辟空间的视角。
注意:void(空)类型不能定义变量,因为内存为空类型所开辟的空间不确定。但是,void *可以用来定义一个指向空类型的指针。因为,所定义的是指针类型,在32位处理器上,内存为指针变量开辟4个字节大小。(即所开辟内存空间大小所确定)
二.数据的存放和读取
存放:不论是有符号数还是无符号数,它们都是以二进制补码的形式存放的。只不过它们的补码形式求法不同。对于无符号数和有符号整数来说,它们的补码就是它们的二进制序列。有符号数有符号位,符号位就是最高位。正数的符号位是0,负数是1.对于有符号负数来说,我们通常先写出它的原码(符号位是1,其它位按照它的绝对值二进制序列来写。),然后通过原码写出补码(符号位不变,其余位按位取反),最后再在末位+1得到补码。

读取:在读取数据时,我们要先看它是什么类型,然后判断类型是有符号数还是无符号数。如果是无符号数,直接读取,把二进制数转化为十进制、八进制、十六进制等。如果是有符号数,先看最高位是1还是0(是负数还是整数),如果是0,则读法与无符号数相同;如果是1,则与有符号负数存储相反,先在末位上减1,然后除符号位外,其它位按位取反。

下面请看几个例题:

1.

分析:在这里定义了三个变量a,b,c,其中a和b都是有符号char型,c是无符号char型。在这里要以十进制有符号整型输出a,以无符号整型输出b,以有符号整型输出c.其中,a,b,c都占1个字节,但输出时的整型都占4个字节,所以要进行类型提升。即添加符号位。根据上面的数据存放,我们很容易知道a,b,c在内存中的存储都是11111111.添加符号位根据数据原有的类型,无符号数添加0,有符号数添加符号位。所以在a前面要添加24个1,b前添加24个1,c前添加24个0.所以它们变为:

a:1111 1111 1111 1111 1111 1111 1111 1111

b:1111 1111 1111 1111 1111 1111 1111 1111

c:0000 0000 0000 0000 0000 0000 1111 1111

下面进行读取:

a以有符号输出,那么先看符号位,最高位是1,所以a是负数,然后以负数来读取

       a:1111 1111 1111 1111 1111 1111 1111 1111

   -1:1111 1111 1111 1111 1111 1111 1111 1110

取反:1000 0000 0000 0000 0000 0000 0000 0001   -->-1

b以无符号整型输出,所以不用看符号位,直接进行读取。

所以输出为4294967295

c以有符号十进制输出,也要看其符号位。最高位是0,所以是正数,读取时直接根据二进制序列读。


例2:

分析:有符号char型的数值取值范围是:-128~127。128表示为二进制序列是1000 0000.而在有符号char型中,-128也是这样表示的,所以在内存中,a认为这里的128就是-128,符号位是1.然后要以无符号整型输出。同样进行类型提升,a前面加24个1,变为:1111 1111 1111 1111 1111 1111 1000 0000

所以输出为十进制整数4294967168.

例3:

分析:首先定义了一个有符号字符数组a,有符号char型的取值范围是:-128~127.然后对a[i]用循环赋值。最后输出a的长度。在这里,要注意字符数组长度以'\0'为标志,其实这里的0就等价于'\0'。所以我们只要计算出当i等于何值时,a[i]=0,就可以知道数组a的长度。下面先一次计算:

i=0时,a[0]=-1;i=1时,a[1]=-2;............i=127时,a[127]=-128;

i=128时,a[i]=-1-128=-1+(-128)

    -1:1111 1111

-128:1000 0000

和 : 10111 1111

但是只能取后8位,即0111 1111=127,所以a[128]=127;

i=129时,a[129]=-1+(-129)

       -1:1111 1111

-129:1 0111 1111

和:  1 0111 1110   同理,只取后8位,即为0111 1110,所以a[129]=126.

同理:a[130]=125,a[131]=124,.........a[255]=0,所以a共有256个元素,且最后一个元素是0,所以a的长度是256-1=255.

三.浮点数的存取

浮点数分为单精度float型和双精度double型,分别占4个字节和8个字节。在这里,我们先讨论单精度float型,double型类似。

1.float型:

存:我们知道,十进制小数可以化为科学计数法,同样,二进制也可以化为科学计数法:(-1)^S*M*2^E。其中S是符号位,取值是0和1;M是有效数字,取值范围在大于等于1和小于2之间;E是指数位。所以,我们存储float型的数据,实际上就是对E、S、M的存储。对于float型,共占4个字节,有32个比特位。其中,最高位存放符号位即S,接下来的8个比特位存放指数位E,剩下的23个比特位用来存储有效数字M.由于E是无符号整型,取值在0~255之间,但其实科学计数法中的E可以是负数,所以我们在存放的时候通常要给原来数据的指数位加上127。规定:计算机内部保存M时,默认这个数字的第一位总是1,因此可以被舍去,只保存后面的小数部分。等到读取的时候再自动加上1.这样就可以节省1位有效数字,对float型来说,留给M只有23位,将第一位的1舍去后,等于可以保存24位有效数字。

取:根据存放的二进制序列,我们可以把数据表示为科学计数法的形式,然后自觉给指数位减去127,有效数字部分加上1,就能够得到原有数据的二进制序列。

2.double型: 

存:先将原有数据化为科学计数法。由于double型数据共占8个字节,64个比特位。所以,它在存储时的精度就叫float型高。其中,最高位S是符号位,值为0或1;接下来是指数位E,占有11个比特位,最后是有效数字部分,占52个比特位。E的取值范围是0~2^11-1(2047)。在存时,也要给数据原有的指数位加上中间数1023。

取:同float数据一样,在把二进制数写成科学计数形式后,自动给指数部分减去1023,有效数字部分加上1.再转化为相应的进制数。

例:

      

分析:pfloat指针是一个指向float型的指针变量,那么*pfloat的值理论上应该是9.000000,怎么会输出0.000000?

9在内存中的存储为:0000 0000 0000 0000 0000 0000 0000 1001,在读取时看作浮点数存储。根据上面的取法,这个float型的数据符号位是0,紧接着的8位0000 0000是加过中间数127之后的指数部分,后面的0000 0000 0000 0000 0001 001是除去1后的有效数字部分,所以原有数据的科学计数表示为:

(-1)^0*1.00000000000000000001001*2^(-127),约等于0,所以输出为0.000000。

后来把*pfloat的内容赋值为9.0,因为9.0=(-1)^0*1.00100000000000000000000*2^3,符号位是0,指数位是3+127=130,二进制为:1000 0010,有效数字部分表示为:0010000 0000 0000 0000 0000,所以9.0在内存中的二进制序列是0 1000 0010 0010000 0000 0000 0000 0000,然后以十进制输出即为1091567616.


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,局部变量和函数参数等数据通常存储在栈空间中。栈空间是一种自动管理的内存区域,用于存储函数的局部变量和函数调用的相关信息。 当一个函数被调用时,它的局部变量和函数参数被分配到栈空间中。栈空间的分配和释放是由编译器自动完成的,遵循"后进先出"(Last-In-First-Out, LIFO)的原则。 在栈空间中,局部变量的存储是通过栈指针(SP)进行的。栈指针指向当前栈顶的位置,新的局部变量被分配在栈顶,并且栈指针向下移动。当函数调用结束后,栈指针会回退到之前的位置,之前的局部变量所占用的空间就可以被重新使用。 要存储读取栈空间中的数据,可以直接使用变量名来进行操作。例如,以下是一个示例函数,展示了如何存储读取栈空间中的数据: ```c void exampleFunction() { int x = 10; // 在栈空间中分配一个整变量x int y = 20; // 在栈空间中分配一个整变量y int z = x + y; // 通过操作栈空间中的x和y计算z的值 printf("z = %d\n", z); // 输出z的值 } ``` 在这个示例函数中,变量`x`和`y`被分配到栈空间中,它们可以通过变量名直接进行操作和计算。最后,通过`printf`函数将计算得到的结果输出。 需要注意的是,栈空间中的数据只在函数执行期间有效。当函数执行结束后,栈空间中的数据将被销毁,并且不能再访问这些数据。因此,栈空间主要用于存储函数调用期间所需的临时数据和局部变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值