当前位置:首页 » 《休闲阅读》 » 正文

整型数据在内存中的存储_Suk_god的博客

2 人参与  2022年02月03日 16:15  分类 : 《休闲阅读》  评论

点击全文阅读


这里写目录标题

  • 整型数据在内存中的存储
    • 预备知识
      • 原码、反码、补码
      • 大小端介绍
        • 定义:
        • 为什么要有大小端?
        • 设计一个程序判断大小端
    • 针对整型数据存储的练习题
      • 1、此代码段输出结果是?
        • 分析
      • 2、求出下面程序的输出结果
        • 分析
      • 4、求程序输出结果
        • 分析
      • 5、继续求程序输出结果
        • 分析
      • 6、求程序输出结果
        • 分析
      • 7求程序段结果
        • 分析

整型数据在内存中的存储

预备知识

原码、反码、补码

计算机中的有符号数有三种表示方式,即原码、反码和补码
三种表示方法各不相同。
原码:直接将二进制按照正负数的形式翻译成二进制即可
反码:原码符号位不变,其余位取反
补码:反码+1
正数的原码反码补码相同

大小端介绍

定义:

大端(存储)模式:数据的低位保存在内存的高地址中,数据的高位保存在内存的低地址中
小端(存储)模式:数据的低位保存在内存的低地址中,数据的高位保存在内存的高地址中

为什么要有大小端?

在计算机系统中,以字节为单位,每个地址单元都对应着一个字节,一个字节为8bit,对于位数大于8位的处理器来说,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

设计一个程序判断大小端

int check_sys()
{
	int i = 1;
	return (*(char*)&i);//首先取到i的地址,强转为char*,再对其解引用
}

int main()
{
	int ret = check_sys();
	if (ret)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	system("pause");
	return 0;
}

结果

针对整型数据存储的练习题

1、此代码段输出结果是?

#include <stdio.h>
int main()
{
    char a= -1;
    signed char b=-1;
    unsigned char c=-1;
    printf("a=%d,b=%d,c=%d",a,b,c);
    return 0;
 }

分析

a,b,c三个变量的初始化值都为-1;

-1的补码:1111 1111 1111 1111 1111 1111 1111 1111

对于a和b来说,char类型和signed char类型一样,故而输出的结果也一样。

首先,内存中存储的是-1的补码,由于char类型只占一个字节,故而在写入内存是发生截断,内存中存储的为二进制序列1111 1111

输出函数以“%d”的形式打印,而从内存中取出来的数据为1111 1111,所以要发生整形提升,比特位由原来的8位提升到32位,整型提升时高位补1还是补0需要看自身类型,a,b为有符号数,故而补1。

所以此时二进制序列变为1111 1111 1111 1111 1111 1111 1111 1111,而又因为数据是按照“%d”(有符号数)打印,看最高位为1,所以说这个二进制序列为结果的补码,我们将其转换为原码后结果为:1000 0000 0000 0000 0000 0000 0000 0001,对应我们十进制的-1,所以,a,b的输出结果均为-1。

对于变量c来说,它的类型为unsigned char,根据前面的思路,数据在写入内存时进行了一样的操作,而从内存取数据时就有所差异了!

取出来的数据依旧是二进制序列1111 1111,发生整形提升时高位补1还是 补0需要看自身类型,由于c是无符号数,所以补0

也就是说,此时的二进制序列从为 0000 0000 0000 0000 0000 0000 1111 1111,又因为数据是按照“%d”(有符号数)打印,看最高位为0,所以此时的二进制序列就是对应的结果,也就是十进制的255。

综上所述,输出的结果是:a=-1,b=-1,c=255
在这里插入图片描述

2、求出下面程序的输出结果

#include <stdio.h>
int main()
{
    char a = -128;
    char b = 128;
    printf("%u\t%u\n",a,b);
    return 0; 
 }

分析

-128 的补码为:1111 1111 1111 1111 1111 1111 1000 0000
128的补码为: 0000 0000 0000 0000 0000 0000 1000 0000

将该数据写入内存时,由于a,b的类型均为 char,所以会发生截断,只将1000 0000存入a中,1000 0000存入b中。

取数据时:将二进制序列1000 0000从内存中取出,由于要以“%u”的形式输出,所以需要对a和b都要做整形提升

由于a,b的自身类型为char,有符号类型且1000 0000高位为1,所以高位补1,形成新的二进制序列为1111 1111 1111 1111 1111 1111 1000 0000

输出函数以“%u”输出,为无符号类型,所以新的二进制序列即为最终结果!对应十进制的4,294,967,168
在这里插入图片描述

在这里插入图片描述

4、求程序输出结果

	int i = -20;
	unsigned int j = 10;
	printf("%d\n",i+j);

分析

按照补码的形式进行计算,最后格式化为有符号整数
-20的补码为:1111 1111 1111 1111 1111 1111 1110 1100
10的补码为:0000 0000 0000 0000 0000 0000 0000 1010
二者相加的二进制序列为:1111 1111 1111 1111 1111 1111 1111 0110

以“%d”输出,二进制序列符号位为1,说以是负数,说明此二进制序列为最终结果的补码,所以将其进行转换,最终结果为:1000 0000 0000 0000 0000 0000 0000 1010,对应十进制的-10。

相应地,这里也间接说明,两个类型不一致的数据做运算时,要发生隐式类型准换,只有类型一致时,才可以进行预算。
在这里插入图片描述

5、继续求程序输出结果

unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n",i);
	}

分析

对于此题来说,首先,变量i的类型是无符号整型数据,for循环中的条件判断为i>=0,表达式左右两边的类型不一致,所以要发生隐式类型转换。
当i逐次递减,减到0的时候,下一次理应为-1,此时从内存中读取出来i的二进制序列为:1111 1111 1111 1111 1111 1111 1111 1111,但是i的类型为无符号整型数据,所以此二进制序列就是最终结果,也就是说此时i的值变成了unsigned int 的最大值;也就是说,每次i递减到0的时候,下一次就会变成unsigned int 的最大值。

综上,此程序代码为死循环,具体输出结果是:
9 8 7 6 5 4 3 2 1 0 4294967295 …0 4294967295…0无限循环。

6、求程序输出结果

int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
   {
        a[i] = -1-i;
   }
    printf("%d",strlen(a));
    return 0; 
}

分析

数组a的容量为1000,每一个元素类型为char,for 循环做的操作是对数组的 每一个单元重新赋值。最后输出的值是strlen(a)

stelen():求字符串长度,以‘\0’(实际存储为数字0)作为结束标志,不包括‘\0’在内。

也就是说,此题的主要问题在于循环经历多少次之后,对数组单元的赋值为0???

我们知道,char类型的数据取值范围为[-128~127],也就是说,只要 -1-i 的值在此范围内,就是合法的。
i = 0---->a[i] = -1
i = 1---->a[i] = -2
以此类推
i=127------>a[i] = -128、

i = 128----->a[i] = -129??? 很明显出错了,超出了char的范围。
-129补码:1111 1111 1111 1111 1111 1111 0111 1111
由于数组类型为char类型,故而发生截断,得到新的二进制序列为0111 1111,重新写回数组a时,判断最高位为0,所以此二进制序列就是最终结果,对应十进制的的127.

也就是说,
i = 128 时----->a[i] = 127
由此可以看出,i不断递增的过程中,a[i]的数据内容从-1递减到-128然后由-128变成127,再由127递减到0

这总共经历了128+128-1(最后一个0不包括在内)长度
所以最终结果为:255

7求程序段结果

#include <stdio.h>
unsigned char i = 0;
int main()
{
    for(i = 0;i<=255;i++)
   {
        printf("hello world\n");
   }
    return 0; 
}

分析

对于循环变量i:它的类型为unsigned char ,取值范围为[0~255]

当i的值为255时,合法,再加1理应为256,对应的原码为1 0000 0000,补码和原码一致,但是在存入时要发生截断,存入的数据实际为0000 0000,对应十进制的0

综上所述:此代码段的结果是发生死循环,因为i 的值从0增长到255再变成0,然后再到255。


点击全文阅读


本文链接:http://zhangshiyu.com/post/34242.html

补码  类型  输出  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1