数据存储之整形存储

简介: 数据存储之整形存储

前言

国庆节的今天又是学习生活中收获满满的一天呢。祝大家国庆节快乐呀,不知道大家今天收获怎么样呢。

今天在学习整形存储的相关知识的时候,发现这块知识点真是陷阱丰富,一不小心就会出错,学完后也不禁发出感慨:哇,原来是这样的。趁着知识还是热乎着的,写篇博客记录一下来巩固知识点。

其实干讲也讲不出所以然,所以用几道例题来讲解分析一下就足够了。话不多说,直接上菜。


以下代码均在Visual Studio 2022 32位环境下编译

一、前提知识

1.原码,反码,补码

每个整数都有三种表达形式,即原码,反码和补码。整数在内存中一般是以补码的形式存储的,关于原码,反码和补码的计算,有以下规律。

正数的原码,反码,补码均相同

负数的反码是原码除符号位外,其它位按位取反,补码则是在反码的基础上+1即可

例如:十进制数21

21的二进制为00000000 00000000 00000000 00010101

这就是21的原码,由于21是正数,故其原反补码均相同

21的原码:00000000 00000000 00000000 00010101

21的反码:00000000 00000000 00000000 00010101

21的补码:00000000 00000000 00000000 00010101

再例如:十进制数 -10

-10的二进制为 10000000 00000000 00000000 00001010

这是原码,由于-10是负数,反码是除符号位外其余位按位取反,所以

-10的反码为:11111111 11111111 11111111 11110101

补码是反码的基础上再+1,所以

-10的补码为:11111111 11111111 11111111 11110110

2.signed和unsigned

signed是有符号的意思,其代表含义是最高位并非数字位,最高位只是判断正负的,0为正,1为负。

unsigned是无符号的意思,它说明二进制数的最高位并未符号位,跟其他位一样,是数字位,unsigned所修饰的数不包含负数。

例如:

signed char 所能表达的范围为:-128~127之间

而unsigned char 所能表达的范围为:0~225之间

一般不写修饰符的时候,都是按有符号类型来的。

3.整型提升

这块不多讲,整型提升就是位数少的跟位数多的数运算时,由于位数不够,需要在前面填充数字,一般有以下规律:

有符号的数在进行整型提升的时候,最前面补和符号位相同的符号,补充到位数足够。

无符号的数在进行整型提升的时候,最前面补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\n", a, b, c);
  return 0;
}

这道题的重点还挺多,然我们一一分析一下。

首先是char a = -1; -1是个整数,整数在内存中都是以补码的形式存储的。

-1在内存中的补码为11111111 11111111 11111111 11111111 占32位,4个字节。

由于a是个char类型,占8位一个字节,所以a会把-1给截断掉,只能取后面的8位,也就是低位的11111111

同理,b和c一样都是11111111但是这些11111111所代表的含义却不是一样的。

a一般是有符号的(取决于编译器),b是有符号的,c是无符号的。

a,b,c在打印中均要求以整形类型打印,但由于a,b,c都只有1个字节,位数不够,只能去进行整形提升,有符号的前面补符号位,无符号的前面补0,所以,最后a,b,c在内存中的补码为:

a:11111111 11111111 11111111 11111111

b:11111111 11111111 11111111 11111111

c:00000000 00000000 00000000 11111111

补码转换成原码再打印出来,则abc的原码为:

a:10000000 00000000 00000000 00000001

b:10000000 00000000 00000000 00000001

c:00000000 00000000 00000000 11111111

则打印出来的数据应该为 -1 -1 225

例题一的结果

2.例题二

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

char 的范围是-128~127之间,a的补码为10000000

%u是按无符号整形打印,首先将a进行整型提升,因为a是负数,所以

a:11111111 11111111 11111111 10000000

又因为要按照无符号打印,所以最前面的就不是符号位了,所以这个数被认为成正数了,也就不需要再转换成原码了。直接打印这个值就行,结果应该是42亿多。

例题二的结果

3.例题三

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

因为有符号的char 的范围是-128~127之间,a的值超出能表示的范围了,128在二进制中的表示为10000000,在char中直接被认作-128了,于是跟例题二一样,这题结果也是42亿多。

例题三的结果

4.例题四

#include<stdio.h>
#include<string.h>
int main()
{
  char a[1000];
  int i = 0;
  for (i = 0; i < 1000; i++)
  {
    a[i] = -1 - i;
  }
  printf("%d", strlen(a));
}

这题要打印字符串a的长度,strlen的功能是一直遍历到\0为止,然后返回从开始到\0之前的字符个数,返回类型是unsigned int。

由题目规律可知,for循环的作用是往char数组里面存放-1到-1000的数。马虎大意的人又以为这里会打印1000!其实不是哈,char的范围就只有-128~127之间。当存放完-128后,下一次存放的-129会被char认为成127的,然后-130会被认为126…最终肯定会把0给存放进去。

然后又因为在char类型中,0是等价于\0的,但不等价 ’ 0 ’ 哦。所以strlen在遍历char数组的时候,遇到0就返回了,所以结果应该是225。

例题四的结果

5.例题五

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

在做过前4道题后,这道题已经很简单了。

unsigned char的范围是0~255之间,而题目中的for循环需要循环256次,而i的值最大也才255,是一直符合循环条件的,所以结果显而易见,将会死循环打印hello world。

例题五的结果


总结

到这里,我们终于讲完了关于整形存储的一些知识点和易错点,其实没想到啊,原来整形提升还蛮细节的嘞,想要真正掌握这方面知识,需要非常了解数据在内存中的存储方式,感觉是很容易被忽略的重点呢。关于浮点数的存储我也打算写一篇。

多的不说,今天国庆节,再次祝大家国庆节快乐!

目录
相关文章
|
2月前
|
存储
数据在内存中的存储之整数存储
数据在内存中的存储之整数存储
26 0
|
8天前
|
存储 编译器
数据存储之浮点存储
数据存储之浮点存储
17 5
|
2月前
|
存储 编译器
关于数据在内存中的存储(整形篇)
关于数据在内存中的存储(整形篇)
59 0
|
7月前
|
存储 编译器 C语言
数据在内存中的存储(包含整型、浮点型在内存中的存储以及大小端的介绍)
数据在内存中的存储(包含整型、浮点型在内存中的存储以及大小端的介绍)
94 0
|
11月前
|
存储 缓存 固态存储
一文看懂存储
一文看懂存储
211 1
|
12月前
|
存储 SQL NoSQL
存储的未来
存储的未来
95 1
|
11月前
|
存储
浮点型在内存中的存储,与整型存储方式竟然不同
浮点型在内存中的存储,与整型存储方式竟然不同
|
12月前
|
存储 编译器 C语言
数据在内存中的存储(1)——整形
数据在内存中的存储(1)——整形
|
12月前
|
存储
整型数据在内存中的存储
整型数据在内存中的存储
|
存储 小程序 编译器
【C 数据存储详解】(1)——深度剖析整形数据在内存中的存储
【C 数据存储详解】(1)——深度剖析整形数据在内存中的存储
84 0