C语言中整形、浮点型数据在内存中的存储和使用

我们在存储数据时首先是声明数据类型,如int,char,long等,声明类型的是向内存申请对应类型大小的一块内存空间,以对数据进行存储。

以下为不同数据类型的空间大小

  • char 1个字节
  • short 2个字节
  • int 4个字节
  • long long 8个字节
  • float 4个字节
  • double 8个字节

而一个字节为八个bit位,对应八个二进制位,因此解释每个数据类型对应的数据范围。

整数类型又有有符号数和无符号数的类型,简单来说,有符号数和无符号数的数据长度范围是一样的,区别在于无符号类型不区分二进制的数据正负,统一转化为正数。

如char类型,unsigned char的范围是-128~127 ,char的范围是0-255。区间长度都是256


首先说整形的存储

整数的转码有三种:原码,反码,补码。

先贴一下鹏哥对这里的解释

他后面又解释到使用时的数据提升等等

但是在我的思考里,这种说法有两点不能对存储的现象进行很好的解释

  1. 对于超出范围的负数,数据的二进制位数如果超出类型的范围,符号位的储存和数据冲突,怎么规定符号位?
  2. 解释数据在范围里循环时比较生硬,比如char类型里(bin)1000 0000如果按照符号位的说法解释为什么是-128是只能说是规定。

因此在思考并验证多次之后,写出我对C语言里数据的存储和不同类型使用方式的思考。(我并没有深度学习原理,这里只是我的思考,并不一定正确,如果之后的学习里能够探得真相,我会有解释。)

首先仍然是三码

  • 原码:根据原来的数据直接转化为二进制得到
  • 反码:将原码按位取反(此时没有符号位)
  • 补码:反码加1

对于正数,存储到内存中三码相同,直接得到原码的二进制序列。

对于负数,并不会储存符号位,在有负号的时候,编译器会将数据去掉符号直接进行原码,反码,和补码的转换,得到二进制序列。

之后,根据申请数据类型的空间大小,储存二进制位数。从低位向高位存储(由于windows的小端字节序的存储方式)。

使用时,根据数据类型,再进行相应的转换

  • 如果是无符号数,直接进行数据的翻译
  • 如果是有符号数,将现有的最高位看成符号位,如果是0,则表示为正数,直接翻译;如果是1,则表示位负数,将数据按照补码转化为原码,再打印加负号的数值。
  • 如果有类型提升,高位补符号位

 这种说法,既解释了为什么超出数据范围的大数为什么常常显示负数,也能很好的解释char类型里(bin)1000 0000为什么是-128

 举例:

int main()
{
	char a = -1;
    unsigned char c = -1;
    printf("%d %d",a,c);
    //结果是-1 255
	return 0;
}

首先-1有负号,则进行原反补的转化0000 0001 -> 1111 1110 -> 1111 1111 分别存入a,c的内存

然后使用时a 首位是1 打印负号,取反为0000 0000-> 0000 0001 打印为1,所以为-1

                  c 由于c是无符号数,直接翻译1111 1111 为255

补充,这里%d使用是整形,要对数据进行提升,不过一个符号位是0,一个没有符号位所以省略

int main()
{
	char n = -128; 
	printf("%u ", n);
	printf("%d", n);
    //结果是4294967168  -128
	return 0;
}

首先仍然128进行原反补转换,1000 0000 -> 0111 1111 -> 1000 0000

使用时为整形,数据提升1111 1111 1111 1111 1111 1111 1000 0000

第一行为无符号数直接转化为4294967168

第二行为有符号数转化 为0000 0000 0000 0000 0000 0000 0111 1111

                                 加1  0000 0000 0000 0000 0000 0000 1000 0000     打印为-128

int main()
{
    char arr[1000];
    for (int i = 0; i < 1000; i++)
    {
        arr[i] = -1 - i;
    }
    printf("%d", strlen(arr));//结果为255
    return 0;
}

这里有一点,数据持续自减,到下限之后会循环

这里从-1开始减到-128 补码为1000 0000

再减1为 0111 1111 首位是0,则为正数,转换为127

再继续减小,到0时存在char类型的数组里,由ASCII表翻译为‘\0’

strlen计算长度为255,正好为char的数据区间


思路捋下来,也没明显的解决什么其实,但是这样对个人来说更方便理解

最让我感到惊奇的是数据加减处理时用到的补码,真是个神奇的东西,对于能把正数负数统一加法处理,这就是理科的魅力吧。


浮点数的储存

首先需要注意一点,浮点数和整数的内存使用视角不一样

int main()
{
    int n = 9;
    float* pn = (float*)&n;
    printf("%d\n", n);//结果是9
    printf("%f\n", *pn);//结果是0.000000
    *pn = 9.0; 
    printf("%d\n", n);//结果是1091567616
    printf("%d\n", *pn);//结果是0
    printf("%f\n", *pn);//结果是9.000000
    //以浮点数的方式拿数据和存数据的方式和整形不一样
    return 0;
}

首先申请空间时的命名n 为整形,其使用内存中数据的角度时整形的存放

当我们取指针pn将其强制转化为浮点型的指针。*pn得到使用浮点型的视角

这里要和数据类型转换 float  m = (float)n;区分开,这是数据层面的转换,而不是内存视角

存储:

首先转化为二进制

        小数点后面的位数的转换是2的(-n)次方

        比如 5.5 为 2^2 + 2^0 + 2^(-1)   则其二进制表示为101.1

其次,根据IEEE规定,任意一个二进制浮点数可以表示称下面的形式:

如5.5,即101.1,首先为整数 s = 0;然后转化为1.011*2^2,则E为2;M为1.011

 

M总归可以进行移位到1.xxx所以可以把小数点前的1省略掉,直接存储后面

由于E可能为负数,因此为了确保E为正数,需要将E加上一个中间数

这是以浮点型视角进行内存的存储

我们回头继续看

int main()
{
    int n = 9;
    float* pn = (float*)&n;
    printf("%d\n", n);//结果是9
    printf("%f\n", *pn);//结果是0.000000
    *pn = 9.0; 
    printf("%d\n", n);//结果是1091567616
    printf("%d\n", *pn);//结果是0
    printf("%f\n", *pn);//结果是9.000000
    //以浮点数的方式拿数据和存数据的方式和整形不一样
    return 0;
}

 当存入9的时候,整形的视角存入补码为0000 0000 0000 0000 0000 0000 0000 1001

*pn 时为-1^0 * 2^(-127)*(1.000 0000 0000 0000 0000 1001) = 0.000000

*pn = 9.0时,存入的为-1^0 * 2^(127+3) * 1.001

内存中为 0100 0001 0001 0000 0000 0000 0000 0000

 因此为这个数


对于浮点数精度的解释,我现在并没有想的非常清楚,很明显它同时受e和m的限制,但是之后的使用中,小数点前后位数的权重,还要继续学习。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C语言,二进制和浮点型乘除计算可以使用相应的运算符来完成。 对于二进制数的乘法和除法,可以使用位运算符进行计算。二进制数的乘法可以使用左移运算符(<<)来实现。例如,将一个二进制数向左移动n位,相当于将该数乘以2的n次方。二进制数的除法可以使用右移运算符(>>)来实现。例如,将一个二进制数向右移动n位,相当于将该数除以2的n次方。这些运算符可以在C语言直接使用,提供了方便的二进制乘除计算的方式。 对于浮点型数的乘法和除法,可以使用乘法运算符(*)和除法运算符(/)来进行计算。C语言浮点型数通常使用float、double或long double类型来表示。这些数值类型支持浮点数的乘法和除法操作。使用乘法运算符将两个浮点型数相乘,会得到它们的乘积。使用除法运算符将一个浮点型数除以另一个浮点型数,会得到它们的商。这些运算符在C语言提供了方便的浮点型乘除计算的方式。 需要注意的是,在进行浮点型数的乘法和除法计算时,可能会出现精度丢失的情况。这是因为浮点数在计算机以二进制形式存储,并且无法精确表示一些十进制小数。因此,在进行浮点型数的乘除计算时,应该注意精度问题,并尽可能使用适当的方式进行处理,以避免计算结果的错误。 总之,在C语言,可以使用位运算符进行二进制数的乘除计算,可以使用乘法和除法运算符进行浮点型数的乘除计算。对于浮点型计算,需要注意精度问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值