小議大小端模式對C語言的共用體結構的影響
1、一些問題
問題1
#include "stdio.h"union {int i;char ch[2];}key;main(){key.i=65*256+66;printf("%c\t%c\n",key.ch[0],key.ch[1]);}答案是B A;為什麼不是A B呢? 在前面的文章中我們已經測試過,X86體繫結構的CPU是小端模式的。比如一個數0x1234,放在記憶體裡按照記憶體位址從低往高實際上是低地址位元組裡放的是0x34,高位元組裡放的是0x12。小端模式和我們平時感覺上的一致,把數位元越高的部分放在地址越高的部分。union類型是共用記憶體的,union中是按照從低到高放的,i=0x4142,也就是低地址中放的是42,高地址中放的是41,按照ch[0],ch[1]的順序輸出就是B
A。如果是大端模式的話就是列印兩個空了,故不會出現A B的情況。
問題2
union myun { struct { int x; int y; int z; }u; int k; }a; int main() { a.u.x =4; a.u.y =5; a.u.z =6; a.k = 0; printf("%d %d %d\n",a.u.x,a.u.y,a.u.z); return 0;}
union類型是共用記憶體的,以size最大的結構作為自己的大小,這樣的話,myun這個結構就包含u這個結構體,而大小也等於u這個結構體的大小,在記憶體中的排列為聲明的順序x,y,z從低到高,然後賦值的時候,在記憶體中,就是x的位置放置4,y的位置放置5,z的位置放置6,現在對k賦值,對k的賦值因為是union,要共用記憶體,所以從union的首地址開始放置,首地址開始的位置其實是x的位置,這樣原來記憶體中x的位置就被k所賦的值代替了,就變為0了,這個時候要進行列印,就直接看記憶體裡就行了,x的位置也就是k的位置是0,而y,z的位置的值沒有改變,所以應該是0,5,6。
問題3
int checkCPU(){ union { int a; char b; }c; c.a = 1; return (c.b == 1); // 小端返回TRUE,大端返回FALSE}
這個就不詳細解釋了,用來判定CPU大小端模式的一個經典例子。
問題4
union {int a[2];long b;char c[4];}s;main(){s.a[0]=0x12345678;s.a[1]=0x23456789;printf("%lx\n",s.b);printf("%x,%x,%x,%x\n",s.c[0],s.c[1],s.c[2],s.c[3]);}
答案是:
12345678
78,56,34,12
問題5
# include <stdio.h>main(){union {long i;int k;char ii;char s[4];} mix ;mix.k=0x23456789;printf("mix.i=%lx\n",mix.i);printf("mix.k=%x\n",mix.k);printf("mix.ii=%x\n",mix.ii);printf("mix.s[0]=%x\tmix.s[1]=%x\n",mix.s[0],mix.s[1]);printf("mix.s[2]=%x\tmix.s[3]=%x\n",mix.s[2],mix.s[3]);return 0;}
答案是:
mix.i=23456789
mix.k=23456789
mix.ii=ffffff89
mix.s[0]=ffffff89 mix.s[1]=67
mix.s[2]=45 mix.s[3]=23
出現f是因為把char型強制轉換成int型輸出,0x89最高位1000 1001最高位為1,轉換為int類型的時候認為是負數,而且數在電腦中是按補碼儲存的,所以自然高位補1了。2、這是一個什麼問題
2.1、共用體結構的意義
問題:
假設網路節點A 和網路節點B 中的通訊協定涉及四類報文,報文格式為“報文類型欄位+報文內容的結構體”,四個報文內容的結構體類型分別為STRUCTTYPE1~ STRUCTTYPE4,如何編寫程式以最簡單的方式組
織一個統一的報文資料結構。
分析:
報文的格式為“報文類型+報文內容的結構體”,在真實的通訊中,每次只能發四類報文中的一種,我們可以將四類報文的結構體組織為一個union(共用一段記憶體,但每次有效只是一種),然後和報文類型欄位統一組織成一個報文資料結構。解答:
typedef unsigned char BYTE;//報文內容聯合體typedef union tagPacketContent{ STRUCTTYPE1 pkt1; STRUCTTYPE2 pkt2; STRUCTTYPE3 pkt1; STRUCTTYPE4 pkt2;}PacketContent;//統一的報文資料結構typedef struct tagPacket{ BYTE pktType; PacketContent pktContent;}Packet;
當多個基礎資料型別 (Elementary Data Type)或複合資料結構要佔用同一片記憶體時,我們要使用共用體;當多種類型,多個對象,多個事物只取其一時(我們姑且通俗地稱其為“n 選1”),我們也可以使用共用體來發揮其長處。把幾種不同類型的變數放到同一段記憶體單元中,這些變數在記憶體中佔用的位元組數可能不同,但都從同一個地址開始存放。也就是使用覆蓋技術,幾個變數互相覆蓋。同一個記憶體段可以用來存放幾種不同類型的成員,但在每一瞬間只能存放其中一種,而不能同時存放幾種。即,每一瞬間只有一個成員起作用,其他的成員不起作用,不能同時存在和起作用。共用體變數中起作用的成員是最後一次存放的成員,在存入一個新的成員後原有的成員就失去了作用。
2.2、大小端模式對共用體的影響 當共用體中有不同類型的變數,用一種變數類型給共用體賦值,但用另一種變數類型讀取共用體的時候就涉及到大小端的問題。比如在問題1中,給int類型的變數i賦值,但通過char類型的數組來讀取時,就要注意位元組序的問題,也就是大小端的問題。