关于union的内存对齐问题,从二进制数分析

今天遇到一个感觉很奇葩的问题,一般都说union是公用内存,然后有下面几个需要注意的点:

1.union是共用储存空间的
2.它分配的空间大小为数据类型的最大字节的最小倍数
3.在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。(这里要注意)


下面看一段代码:


#include <iostream>
using namespace std;
union lia
{
    int s;
    double b;
}li;
int main()
{
    li.b = 45;
    li.s = 3072;
    cout << li.s << endl << li.b << endl;  
}

输出结果为:

3072
45

不知道你们会不会有奇怪呢?在前面的第三个知识点说"同一时间只能储存其中一个成员变量的值",那这个为什么输出的两个值都正确呢?


在来看一下这个:

如果把上面的第10行和第11行换一下位置,结果会是什么样的呢?


#include <iostream>
using namespace std;
union lia
{
    int s;
    double b;
}li;
int main()
{
    li.s = 3072;
    li.b = 45;
    cout << li.s << endl << li.b << endl;
}

输出结果:

0
45

这个结果到还是和上面的知识点说的是一样的,那到底是为什么呢?


首先请在注意三个东西:

1. union内存地址对齐是从低地址对齐开始的;

2. IEEE规定单精度浮点数(float) 的格式是:   1位符号位+8位指数位 +23位尾数位(总共四字节,32位),而且采用隐藏位为1

3. IEEE规定双精度浮点数(double) 的格式是:   1位符号位+11位指数位 +52位尾数位(总共八字节,64位),而且采用隐藏位为1


我们就来看看3072这个双进度浮点数的内存分布:

3072 = 1.5 * 2^11

那么:  符号位 : 0(正数)

           指数位: 11+10 = 21 ,所以为 :000 000 101 01 (21)

           尾数位: 1000```0(51个0),这里表示十进制的0.5

而45(10) = 101101(2) 


低地址对齐,这样45就会覆盖掉尾数位的后六位000000为101101,但是这个浮点数的精度太低了,以至于编译器会省略掉,所以,输出来的结果还是原来的3072;

可是,如果是第二种情况,那么3072的最后六位就会全部变为0,这样,原本45就会变为0 了


如果大家觉得有问题,这里可以在做一个测试:


#include <iostream>
using namespace std;

union lia
{
    int s;
    double b;
}li;
int main()
{
    li.b = 45;
    double bb = li.b;
    li.s = 3245;
    cout << li.s << endl;
    cout << li.b << endl;
    cout << bb << endl;
    if(li.b == bb)
        cout << "equal" << endl
    else
        cout << "not equal" << endl;//事实证明他们是不相等的,也就是说li.s赋值的时候改变了,原来的值

    /*//这里是用来证明 == 会进行二进制层面的比较,即:比较每一个二进制位,因为你可能会说浮点数直接的比较是不能用==直接进行,但是用==表示它会进行所有二进制位的比较
    double b,c;
    b = 4.0;
    c = 4.0;
    cout << (b == c) << endl;//输出为1,表示它们是相等的
    */
}

建议:有时候,我们如果要验证一个东西,就需要从他们的本质上来验证,而不是别人所谓的经验


另外:

  整型数据在内存中的存放形式

如果定义了一个整型变量i:

int i;

i=10; 

 

0

0

0

0

0

0

0

0

0

0

0

0

1

0

1

0

 

数值是以补码表示的:

n         正数的补码和原码相同;

n         负数的补码:将该数的绝对值的二进制形式按位取反再加1。

例如:

求-10的补码:

10的原码:

0

0

0

0

0

0

0

0

0

0

0

0

1

0

1

0

      取反:

1

1

1

1

1

1

1

1

1

1

1

1

0

1

0

1

再加1,得-10的补码:

1

1

1

1

1

1

1

1

1

1

1

1

0

1

1

0

由此可知,左面的第一位是表示符号的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值