https://blog.csdn.net/debugzzj/article/details/81705755
相信學過C語言的程序員對C語言的各種數據類型都非常熟悉,像數組、結構體、結構體數組、結構體指針這些數據類型大家都會信手捏來。然而,有些數據類型被我們不經意的邊緣化了。它們沒有數組、結構體這些數據類型用的廣泛,但是卻不容忽視,例如,枚舉、聯合等。
今天我們就討論一下union(聯合)這個數據類型。C語言的發明者為什么要弄一個這種不常用甚至幾乎不用的數據類型呢。下面給你答案。首先,看一下union的定義。
union Data {
int i;
char str[4];
} data;
它有什么屬性呢? 這段代碼定義了一個名為data的union變量。它有什么屬性呢?
1.這個變量在內存中占用4個字節的空間而不是8個;
2.有兩個數據成員:int類型變量的i和char類型的數組str;
3.雖然有兩個數據成員,但是這兩個成員的存儲空間是一樣的。
上面三點是union變量的最基本也是最重要的屬性。詳細說一下第三點。因為union不論包含多少個多少種數據類型,它實例化為變量后,這個變量的長度是這個union中最長的數據類型的長度。下面的代碼定義了一個union變量。它的長度是16個字節。
union DEMO{
char status;
int a;
int serial[4];
}demo;
上面這個表格代表內存中的數據,demo.status 的值為0x1;demo.a的值為,0x4321。以此類推demo.serial的值就出來了。這個屬性是union特有的。
C語言的發明者為什么要弄這么個數據類型呢?現在知道了吧。因為這個union特有的屬性可以幫助我們節省好多行代碼。而且還不用各種基礎數據類型轉換。
union的應用
設想用C語言實現這樣一個功能。我需要用單片機讀取一個監控溫度的i2c slave的寄存器數據。這個寄存器是12位有效位寄存器。讀出來之后我們要通過數據手冊給定的公式計算成實際溫度(設想這個公式為 temp = reg_val *10)。我們怎么實現呢?要知道,i2c的數據傳輸是按照byte傳送的,也就是說,你只能用char類型結束數據,說白了,每個時序你只能接收8個bit的數據。所以12個bit需要讀兩次,用兩個char類型變量或一個char類型數據接收。
- 讀出寄存器數據(這個不在這篇文章的討論范圍內)
- 將讀出的數據轉換成可計算的數據類型(兩個char類型轉換成一個short或int或float類型)
- 根據公式計算
下面看一下不用union實現的函數
int fun( void )
{
int tmp_value = 0;
char reg_val[2] = {0,0};
....
i2c.read(addr<<1, reg_val, 2);
tmp_value = (reg_val[1]<<8 | reg_val[0]);
return tmp_value*10;
}
用union的
union REG_VAL {
int value;
char buf[2];
}reg_val;
int fun( void )
{
int tmp_value = 0;
char reg_val[2] = {0,0};
....
i2c.read(addr<<1, reg_val.buf, 2);
return reg_val.value*10;
}
不用union的函數也可以用sprintf實現,那就更麻煩了。
可以看到雖然在這里用union的代碼比不用union的多了幾行,但是i2c sensor如果多的話,那就會少很多,而且i2c sensor的寄存器有效位數不是一樣的,這個用兩個char類型就解決了,但是其他的可能需要用三個,所以用最上面定義的union變量可以很好的實現,不需要考慮各種轉換問題。
union還是很有用處的,所以不要忽視它了。