类型强转和地址强转

   日期:2024-12-26    作者:c3pw8 移动:http://ljhr2012.riyuangf.com/mobile/quote/37834.html

1 例子

     最近在干一个很复杂的事—读4w多行的项目源码,头都大了有木有!其中有一步是加载一个二进制文件,为了更好的理解代码的含义,我需要一点一点解析二进制文件。在解析到某个位置的时候,有个读浮点数的操作,对应的二进制值为:…CAF249F1…。非常好奇这个值对应的浮点数是多少,所以写代码去求解一下。这里我没有犯一个错误:原始的文件中是按照从低字节到高字节排序的,所以实际的数应该为:0xF149F2CA。但是还是犯了很多错误,最初的代码为

 

想法是通过隐式类型强转获得对应的浮点数,但输出结果为:a is 4048155338,b is 4048155392.000000,完全不是想象中的样子。隐式的类型强转只是将一个int型的数变成一个和原值接近的浮点数,而不是将原始的int值按照地址解析成浮点数。后来一想也对,要不这样强转还有什么意义。注意强转的结果并不和原值一样,这是由float类型的精度造成的,后面我们会详细介绍其中的原理。

     上述方法不行,我又想到利用字符串进行转换,代码如下

 

想法也很简单,将连续四个字节利用atof函数解析成浮点数,输出结果为:a is caf249f1,b is 0.000000,再一次不正确!后来仔细查看atof的解释才明白,原来atof函数只能解析符合浮点数书写格式的数,例如0.0314或者3.14E-2。如果字符串完全无法被转换为数字,则返回0。

     连续两次都没有解决,我怒了!想了一种操作地址的方式,代码如下

 

代码的思想是首先获得int型的地址,然后将该地址强转成float型地址,然后再获得float的值,这样应该不会错了,输出的结果为:a is 4048155338,b is -1000000015047466219876688855040.000000。这个结果可能不太直观,但是我知道这就是我想要的结果。b输出了一个很大的负数,如果将其转换成科学记数法则为-1E30,正好在代码中有个LOG_ZERO的宏定义为该值,正好对应起来了。该浮点数的含义是对某个变量赋初值,初值为log(0)的近似定义。

2 类型强转

符号阶码尾数

如果是单精度(float)类型,上述格式的符号部分为1位,阶码部分为8位,尾数部分为23位;如果是双精度(double)类型,符号部分为1位,阶码部分为11位,尾数部分为52位。

    根据阶码的不同,被编码的值可以分为三种情况(最后一种情况有两个变种)。此外,要注意下面的表是IEEE的浮点数表示,而不是原始浮点数的表示。

2. 非规格化的

非规格化数有两个用途。首先,它提供了一种表示数值0的方法,因为使用规格化数,我们必须总是使>=1,因此我们就不能表示0。当阶码和尾数都为0时就表示0,不过符号位的不同会产生+0.0与-0.0。其次,非规格化可以表示非常接近于0.0的数。

在《深入理解计算机系统》P72有一个很详细的例子,建议大家仔细阅读。

    讲了这么多,我们现在应该明白为什么整数强转成浮点数之后会有精度损失。这是因为float在计算机表示中尾数(float的有效位)只有23位,而int整数有32位,这就导致在将int转换成float的时候,int的低位就会被truncate,最大可能会产生511的误差。

    当然并不是所有的强转都会导致精度损失,这也和整数值的有效位数相关,具体指的是前置1和后置1之间的部分。下面给出一个例子:

 

上述代码的输出为:a is 1048592, type cast of a  is 1048592.000000, b is 134217736, type castof b is 134217728.000000。可以看到a在强转的时候没有精度损失,但是b在强转时产生了精度损失。这是因为a的有效位数小于23位,在强转时float的尾数可以容纳;但是b的前置和后置1之间的位数为23位,这样在强转的时候最低位的1就会被truncate,从而结果产生了8的误差。

    上述误差的产生是由尾数位数过少造成的,针对float类型的阶码部分,我们能有什么收获呢?利用类型强转将int转成float之后,阶码部分就保存了这个整数的最高位次,因而我们可以用阶码来求整数的前置1位置,我会在后面的博客中详细介绍整数前置1的位置求法。

3 地址强转

    地址强转算是一项比较高级的操作,直接将原始地址的类型进行改变。语法也比较复杂,首先通过&符号获得原类型的地址,然后通过(type*)将地址类型进行强转,最好再利用*取值获得新类型的值。这种强转在大多数情况下都没有意义,但是一种情况例外,即在将float的地址强转成int地址时会有特殊意义。


特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号