關於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 |
由此可知,左面的第一位是表示符號的。