處理器間通過訊息(對於C/C++而言就是定義的結構體)進行通訊時需要注意位元組對齊以及位元組序的問題。
1、位元組對齊1.1位元組對齊某些處理器不允許16位和32位的資料在記憶體中任意排放。例如,Motorola 68000 處理器不允許16位的字存放在奇地址,否則會觸發異常。通常32位的處理器通過匯流排訪問(包括讀和寫)記憶體資料。每個匯流排訪問周期可以訪問32位記憶體資料。記憶體資料是以8位的位元組為單位存放的。假如一個32位的資料沒有在4位元組整除的記憶體位址處存放,那麼處理器就需要2個匯流排周期對其進行訪問。通過合理的記憶體對齊可以提高訪問效率。大多數編譯器提供記憶體對其的選項供使用者使用。這樣使用者可以根據處理器的情況選擇不同的位元組對齊。例如C/C++編譯器提供的#pragma pack(n) n=1,2,4等,讓編譯器在產生目標檔案時,使記憶體資料按照指定的方式排布在1,2,4等位元組整除的記憶體位址處。然而在不同編譯平台,或者不同處理器上,位元組對齊會造成訊息結構長度的變化。現在假設使用者定義結構體如下:struct Message{ short opcode; char subfield; long message_length; char version; short destination_processor;};由於為了位元組對齊而進行的填充是通過編譯器進行的編譯器可以將上述結構填充成:struct Message{ short opcode; char subfield; char pad1; // Pad to start the long word at a 4 byte boundary long message_length; char version; char pad2; // Pad to start a short at a 2 byte boundary short destination_processor; char pad3[4]; // Pad to align the complete structure to a 16 byte boundary};也可能填充成其他形式。如此,不同編譯平台,處理器間資料通訊的風險就不必說了吧。1.2處理方法以下以32位處理器為例,提出一種記憶體對齊方法。對於本地使用的資料結構,為提高記憶體訪問效率,採用四位元組對齊;同時為了減少記憶體的開銷,合理安排結構成員的位置,減少四位元組對齊導致的成員之間的空隙,降低記憶體開銷。對於處理器之間的資料結構,需要保證訊息的長度不因為在不同編譯平台和不同處理器導致訊息結構的長度發生變化,使用一位元組對齊對訊息結構進行緊縮;為保證處理器之間的訊息的資料結構的記憶體訪問效率,採用位元組填充的方式自己對訊息中成員進行四位元組對齊。資料結構的成員位置要兼顧成員之間的關係、資料訪問效率和空間利用率。順序安排的原則是:四位元組的放在最前面,兩位元組的緊接最後一個四位元組成員,一位元組緊接最後一個兩位元組成員,填充位元組放在最後。舉例如下:typedef struct tag_T_MSG{ long ParaA; long ParaB; short ParaC; char ParaD; char Pad; /* 填充位元組 */} T_MSG;2、位元組序:2.1、位元組序小尾(Little Endian)就是低位位元組排放在記憶體的低端,高位位元組排放在記憶體的高端。例如對於一個4位元組的整數Byte3 Byte2 Byte1 Byte0將在記憶體中按照如下順序排放: Base Address+0 Byte0 Base Address+1 Byte1 Base Address+2 Byte2 Base Address+3 Byte3Intel處理器大多數使用小尾(Little Endian)位元組序。大尾(Big Endian)就是高位位元組排放在記憶體的低端,低位位元組排放在記憶體的高端。例如對於一個4位元組的整數Byte3 Byte2 Byte1 Byte0將在記憶體中按照如下順序排放: Base Address+0 Byte3 Base Address+1 Byte2 Base Address+2 Byte1 Base Address+3 Byte0Motorola處理器大多數使用大尾(Big Endian)位元組序。網路位元組序:TCP/IP各層協議將位元組序定義為大尾,因此TCP/IP協議中使用的位元組序通常稱之為網路位元組序。2.2處理方法網路位元組序作為一個標準位元組序,如果系統並沒有提供相關的轉換函式,我們可以通過以下4個宏實現本地位元組序和網路位元組序的相互轉換:htons():將16位不帶正負號的整數從本地位元組序轉換成網路位元組序 htonl():將32位不帶正負號的整數從本地位元組序轉換成網路位元組序ntohs():將16位不帶正負號的整數從網路位元組序轉換成本地位元組序ntohl():將32位不帶正負號的整數從網路位元組序轉換成本地位元組序#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)#define htons(A) (A)#define htonl(A) (A)#define ntohs(A) (A)#define ntohl(A) (A)#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)#define htons(A) ((((uint16)(A) & 0xff00) >> 8) | \ (((uint16)(A) & 0x00ff) << 8))#define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | \ (((uint32)(A) & 0x00ff0000) >> 8) | \ (((uint32)(A) & 0x0000ff00) << 8) | \ (((uint32)(A) & 0x000000ff) << 24))#define ntohs htons#define ntohl htohl#else#error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."#endif