今天遇到一个感觉很奇葩的问题,一般都说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 |
由此可知,左面的第一位是表示符号的。