今天遇到一个感觉很奇葩的问题,一般都说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,表示它们是相等的 */ }
关于union的内存对齐问题,从二进制数分析,布布扣,bubuko.com
原文:http://blog.csdn.net/cs_polebear/article/details/20553581