整形在内存中的存储-原码补码反码的理解与应用

news/2025/2/16 6:34:38/

目录

一、概论

1.1 C语言中基本的数据类型

1.2 类型的基本归类

二、整形在内存中的存储

2.1 原码、反码、补码

2.2 存储补码和大小端存储

三、计算各基本数据类型的范围计算原理

3.1 有符号类型的整形范围

3.2 无符号类型的整形范围

3.3 例题


一、概论

C语言提供了非常多的数据类型,我们可以用sizeof来计算它们在内存中所占的字节数,我们今天想要深入了解它们存储的底层原理。

1.1 C语言中基本的数据类型

char - 字符型 所占字节为1
short - 短整型 所占字节为2
int - 整形 所占字节为4
long - 长整型 所占字节>=4,通常为4或8
long long - 更长的整形 所占字节为8
float - 单精度浮点型 所占字节为4
double - 双精度浮点型 所占字节为8

类型的意义:

1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。

2. 如何看待内存空间的视角。

简单来说,我们要搞明白不同数据类型是怎么存进去的怎么拿出来的

1.2 类型的基本归类

整形家族:
charunsigned charsigned char
shortunsigned short [int]signed short [int]
intunsigned intsigned int
longunsigned long [int]signed long [int]浮点数家族:
float
double构造类型:
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union指针类型:
int *pi;
char *pc;
float* pf;
void* pv;空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。

二、整形在内存中的存储

2.1 原码、反码、补码

1)原码、反码、补码就是整数的二进制序列;

2)正整数的原码、反码和补码完全一致;

3)负整数的原码、反码和补码不一样,需要相互转换。

4)内存中存储的是补码,拿出来用的是原码

下面我们分别定义正整数a=10,负整数b=-10,由于是int类型,它们都占4个字节,用32个二进制位表示

a的二进制序列,也是它的原码、反码、补码:

b的原码、反码和补码:

结论:

1)正整数的原码、反码和补码是一致的;

2)负整数的原码转化把符号位以外的二进制位按位取反得到反码,反码+1得到补码。

2.2 存储补码和大小端存储

数据在内存中存储,以十六进制位表达:

内存中存储的是变量的补码,我们来验证一下,把a和b的补码转化为十六进制位:

注:a是正数,a的原码反码补码一致。

 注:b是负数,要先写出-10的原码,然后转化为反码,反码再转化为补码。

 验证一下:

结果表明内存中存储的是补码,但是是反过来存储的,这就涉及到大小端字节序的概念

大端存储:数据的位保存在内存的地址中,位保存在内存的地址中。

小端存储:数据的位保存在内存的地址中,位保存在内存的地址中。

对于a来说,

对于b来说,

因此a和b的大端字节序和小端字节序存储分别是:

 

 结论:在当前电脑的机器环境下,数据在内存中是以小端字节序存储的。

一道判断大小端存储的面试题:

请简述大小端字节序的概念,并设计一个程序判断当前机器的字节序。

在上面解释了大小端的概念,那如何判断当前机器的字节序呢?我们想要得到当前变量在内存中存储的十六进制序列,为了这个序列尽可能的简单,我们就定义一个整形变量让它的值为1,那么整形1的十六进制表达是0x00000001

如果是小端字节序存储,那么就是 (低地址) 01     00      00      00(高地址) 

如果是大端字节序存储,那么就是 (低地址) 00     00      00      01(高地址)

我们只想访问其中1个字节,得到整形1的高位(或者低位),解引用看一看到底是1还是0,那么就能判断到底是大端存储还是小端存储

原本的变量是int*类型的,*解引用后得到的是4个字节,那么我们将其强制类型转化为char*类型,*解引用后就只得到1个字节

int main()
{int a = 1;char* p = (char*)&a;if (*p == 1){printf("小端字节序存储\n");}else{printf("大端字节序存储\n");}return 0;
}

三、计算各基本数据类型的范围计算原理

 

参考来源:https://www.cnblogs.com/luofay/p/6070613.html

注:1个字节的类型的二进制序列有8位,2个字节的有16位,4个字节的有32位,8个字节的有64位,由于变量在内存中存储的是补码,补码的二进制序列和对应类型所占的字节数量有关,因此各基本数据类型的范围和它们所占字节的大小有关。

3.1 有符号类型的整形范围

我们以char类型举例:

char类型由于只占1个字节的内存,所以它的二进制序列只有8位,所以我们容易列举出char类型二进制序列的所有可能,即从00000000~11111111。

我们一般默认char就是signed char,就是有符号的char,因此它的二进制序列的第一位要看成符号位,那么01111111和1000000就应该是char类型范围的两个边界,如图所示: 

 其实,在这255组可能的序列中,我们除了10000000这个序列无法正常计算出它的原码,其他254组二进制序列我们都可以用正数原反补相同、负数要相互转化的原理来计算出它们的原码以及对应的十进制数,所以规定10000000这个序列的原码对应的十进制数为-128。

因此有符号char类型的范围就是-128~127

剩下short类型、int类型、long类型和long long类型的范围计算原理是一致的,只不过由于它们所占字节数不同,就要用不同长度的二进制序列表示,二进制序列一长,2的所占权重可能就增大,所以范围就相应地比char类型要大的多了

int类型的范围是-2^31 ~ (2^31-1),short类型的范围是-2^15 ~ 2^15-1

3.2 无符号类型的整形范围

我们容易观察表知,无符号类型的范围就是0~a,a是对应有符号类型的范围的长度

比如char的范围是-128~127,unsigned char的范围就是0~255;int的范围是-2^31 ~ (2^31-1),unsigned int的范围就是0~2^32-1;short的范围是-2^15 ~ 2^15-1,unsigned short的范围是0~2^16-1等等。

我们以unsigned char类型举例,与char进行对比:

由于是无符号类型,所以第一位就不需要看成符号位,因此在内存中存储的补码和拿出来用的时候的原码是一致的。

3.3 例题

解题步骤:

1)先写出变量值的原码;

2)根据是正数还是负数,写出反码和补码;

3)根据变量的类型,判断数据是否完全存储进这个变量,不完全存储则发生截断

4)观察这个变量是有符号类型还是无符号类型,对应地发生整形提升:有符号位高位补符号位,无符号位高位补0

5)观察是以什么方式打印出来的(以什么方式使用)以及变量本身是有符号还是无符号,根据补码计算出原码。

例题一

int main()
{char a = -1;signed char b = -1;unsigned char c = -1;printf("%d\n%d\n%d\n", a, b, c);return 0;
}

解:a和b是一致的,在vs环境下char就是signed char,因此a和b打印出来是一样的。

c是无符号类型,所以在整形提升和最后的原码计算方面和a、b不一致。

 

 例题二

int main()
{char a = -128;printf("%u", a);return 0;
}

解:

例题三 

int main()
{char a = 128;printf("%u", a);return 0;
}

解: 

 

 例题四

int main()
{int i = -20;unsigned int j = 10;printf("%d", i + j);return 0;
}

 解:由于此时i和j都是int类型,可以完全存储数据,所以不需要发生截断

 

 例题五

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

解:

这是一个死循环,说明循环不仅仅是正常从9执行到0。

i是无符号整形,说明i恒为正数,前9到0是正常的打印,后面的负数有可能转化为正数,所以我们考虑负数转为无符号整数打印出来的是怎样的数。

而且此时也不需要发生截断。

 

 

 


http://www.ppmy.cn/news/393999.html

相关文章

WinCE

http://www.blog.edu.cn/user2/51303/archives/2005/1038252.shtml

wifi sae

学一点Wi-Fi:SAE_NIMEI583的博客-CSDN博客_wifi安全性sae

Wide

Wide 部分是一个广义线性模型,因为具有非线性特征变换功能,而广泛应用在分类和回归上。通过特征之间的组合来对用户的兴趣进行排序是十分有效和可解释的,然后依赖大量的特征工程。相对于线性模型而言,DNN不强依赖人工特征&#xf…

html快照抓取,完整网页快照抓取

完整网页快照抓取 很简单!只需单击鼠标右键,在网页上的按钮! 在任何时候,只要按住鼠标右键,并立即唤出快速拖拽的功能面板,那么你将能够选择所需要的功能,以完成相应的事情。在所采用的方法是鼠…

Maurice Wilkes

EDSAC计算机之父——Maurice Wilkes 作者: baiyuzhong 分类:IT名人堂 阅读:1,459 次 添加评论 1951年5月15日,在英国,BBC频道播出了三个人的演讲,其中有两位大名鼎鼎:一位是计算机科学之父艾伦图…

WES(上)

二代测序中人全基因组外显子测序的流程主要为DNA的提取,将提取到的DNA制作成基因文库,将目标DNA片段进行富集,cluster(/DNB)的生成,测序与数据分析。在RNA的测序环节还包括将RNA其转化成cDNA的过程等(全转录物组鸟枪法…