Bootstrap

原码反码补码详解 -浮点数的表示方法 -数据截断、溢出和提升(全网最全)_浮点小数的二进制补码(2)

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

当然一些小伙伴也会疑问,我给无符号数赋值一个负数会怎么样呢,嘿嘿,我也不知道,试试看。

当X= -1,其二进制表示为 11111111 ,可以看到-1和255的二进制表示方法是一样的。

我们来分析一下 -1 = (10000001)原码 = (11111111)补码

因为在计算机中所有整形都是通过补码的形式进行存储的 ,所以 -1会被表示成 (11111111)补码

如果我们使用 printf(“%d”,X) 打印该值,我们会发现打印出来的是255,因为打印X时,会将其认定为 unsigned char型,而-1补码和255的二进制表示是一样的,所以会打印出255。

为了验证,我们再对一个负数进行测试

当X = -15,其二进制表示为 11110001,使用 printf(“%d”,X) 打印该值打印出的值为241

再看一下当X= 241,其二进制表示为 11110001

X= -15 = (10001111)原码 = (11110001)反码

可以看出和我们上面的想法是一致的。

通过上面我们也可以得出一个结论:在C语言中,整型数据的存储都是使用补码来jing

四、溢出和截断,数据类型的转换

首先我们将C语言中所有的基本数值数据都列举出来,来看看它们之间的运算转换。

  1. 整形类的

    • 有符号数:char, short, int, long
    • 无符号数:unsigned char, unsigned short, unsigned int, unsigned long
  2. 浮点类的

    • float,double

不同数值类型之间的运算

一般我们都是对相同数据类型的数值之间进行+,-,*,/运算。比如:int和int之间进行加减乘除运算,但是不同数据类型之间进行加减乘除运算也是很常见的。下面我们就来了解一下不同数据类型之间运算的规则。

  1. 若一个运算符两侧的数据类型不同,则先自动进行类型转换,使两者具有同一类型,然后进行运算。
  2. 自动类型转换的规则是将低精度的数据转换成高精度的数据

数据低精度和高精度的概念:对于整型数据char的精度最低,long的精度最高

整型数据之间的精度由低到高排序为:char < short < int < long

浮点数据之间的精度由低到高排序为:float < double

任何整型的数据精度都小于浮点数据,因此总的数据类型精度排序为:char < short < int < long < float < double

上面的排序还没有考虑到无符号数的精度排序,因为无符号数这边稍微有点复杂我们后面再单独讲。
3. 具体运算规则:

* 当两个不同整型数据类型进行运算时,将低精度的整型数据转换成高精度的整型数据再进行运算;
* 当整型和浮点型进行运算,不管浮点是float还是double,都将进行运算的整型和浮点转成double进行运算;
* Char型与int型数据进行运算,就是把字符的ASCII码与整型数据进行运算

 如:12+‘A’=12+65=77
* 两个int型相除,不管是否有余数,结果都为整型;如:5/10 输出是整数部分:0

下面我们用代码来测试一下:

#include <stdio.h>
int main ()
{
	char a1 = 'A', a2 = 'B';
	short s1 = 55, s2 = 66;
	int i1 = 555, i2 = 666;
	float f1 = 2.72, f2 = 22.72;
	double d1 = 3.14, d2 = 31.45;
	
    printf("%d",sizeof(X));
}

sizeof(char) = 1 sizeof(short) = 2 sizeof(int) = 4 sizeof(float) = 4 sizeof(double) = 8

sizeof(a1 + a2) = 4 两个char相加后变成了int,4个字节

sizeof(a1 + s1) = 4 char和short相加变成了int,4个字节

sizeof(s1 + s2) = 4 short和short相加变成了int,4个字节

sizeof(a1 + i1) = 4 char和int相加变成了int,4个字节

sizeof(i1 + i2) = 4 int和int相加变成了int,4个字节

sizeof(i1 + f1) = 4 float和float相加变成了float,4个字节

sizeof(i1 + d1) = 8 int和double相加变成了double,8个字节

sizeof(a1 + d1) = 8 char和double相加变成了double,8个字节

可以看出,当不同整型数据运算时,都优先向int转换;当涉及到浮点数时,则转成浮点数。

整型提升是C程序设计语言中的一项规定:在表达式计算时,各种整形首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型;然后执行表达式的运算。


数据的溢出、截断、提升

**溢出:**指给某个变量赋值时,超出了该类型变量所能表达的范围,比如:

unsigned char a;
a = 260;//a的取值范围是0~255,使a=260就会导致数据溢出,a最终得到的是一个错误的值;

对于整型溢出,分为无符号整型溢出和有符号整型溢出。

对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”,也就是说,如果一个unsigned char(1字符,8bits)溢出了,会把溢出的值与256求模。例如:

unsigned char x = 0xff;
printf("%d\n", ++x);

对于signed整型的溢出,C的规范定义是“undefined behavior”,也就是说,编译器爱怎么实现就怎么实现。对于大多数编译器来说,算得啥就是啥。比如:

signed char x =0x7f; //注:0xff就是-1了,因为最高位是1也就是负数了
printf("%d\n", ++x);

上面的代码会输出:-128,因为0x7f + 0x01得到0x80,也就是二进制的1000 0000,符号位为1,负数,后面为全0,就是负的最小数,即-128。

另外,千万别以为signed整型溢出就是负数,这个是不定的。比如:

signed char x = 0x7f;
signed char y = 0x05;
signed char r = x \* y;
printf("%d\n", r);


提升:提升是将占字节小的元素赋给占字节大的元素时出现的补位现象。

#include <stdio.h>
int main ()
{
    char a = -50;//a的补码为11001110
    short b = a;
    int c = a;
    
	printf("%d\n",b);//打印值为-50,补码为11111111 11001110
	printf("%d\n",c);//打印值为-50,补码为11111111 11111111 11111111 11001110
}

可以看出对于负数来说,提升是使用低位填充,高位补1的操作。

对于正数,则是低位填充,高位补0的操作。

#include <stdio.h>
int main ()
{
    char a = 50;//a的补码为 00110010
    short b = a;
    int c = a;
    
	printf("%d\n",b);//打印值为50,补码为00000000 00110010
	printf("%d\n",c);//打印值为50,补码为00000000 00000000 00000000 00110010
}


截断:指给某个变量赋值时,超出了该类型能表达的范围,如果采取截断策略,则变量只保留数据中低字节的数据,高字节的数据则会丢弃,即截断是将所占字节大的元素赋给所占字节小的元素时会出现数值的舍去现象。比如

#include <stdio.h>
int main ()
{
	int a = 1431655765; //a的补码为01010101 01010101 10110101 01010101
	short b = a;
	char c = a;
	printf("%d\n",b);//b打印的值为-19115,二进制补码为10110101 01010101
	printf("%d\n",c);//c打印的值为85,二进制补码为01010101
}

可以看出截断的规则是先填充低位,截断高位。


五、联合体实例

下面我们以联合体为例,来讲解一下上面知识的应用。

首先看两段代码:



![img](https://img-blog.csdnimg.cn/img_convert/e968d7e1c7844f61def82c651cbe638e.png)
![img](https://img-blog.csdnimg.cn/img_convert/b906c7fd92e022908047b163efec0d11.png)
![img](https://img-blog.csdnimg.cn/img_convert/b313c5bb303187d0c87e9eb89c32dcba.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

15545484072)]
[外链图片转存中...(img-u321NFmo-1715545484072)]
[外链图片转存中...(img-0oq7Kelt-1715545484073)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;