python結構體位元組對齊 八字節對齊

2021-10-13 14:15:03 字數 3703 閱讀 7948

位元組對齊意義

在進行c/c++開發時,特別是要求跨平台或者網路通訊的時候,都會要求進行位元組對齊,那為什麼需要對齊,如果不對齊會有什麼問題呢。

(1) 儲存方式:

現代計算機處理器對儲存的讀取都是按照特定大小位元組去讀寫(稱其為乙個儲存單元),比如乙個變數char,它的長度為1,但是在儲存器中它占用的空間是乙個儲存單元。

當變數位元組長度小於等於乙個儲存單元時,都將分配乙個儲存單元,且儲存空間永遠是儲存單元的整數倍。

(2)讀寫效率:

cpu訪問記憶體都是一次訪問乙個儲存單元,比如32位linux系統乙個儲存單元為4位元組,當需要讀取乙個int資料時,只需要讀取一次,如果儲存單元為1位元組,則需要讀取4次,

通過移位等運算計算出乙個int值,同樣的讀取乙個int值,其訪問記憶體及運算的次數遠遠低於一次讀取乙個位元組。

(3)跨平台問題:

各個硬體平台對儲存空間的處理不盡相同,比如一些cpu訪問特定的變數必須從特定的位址進行讀取,嵌入式arm架構和我們平時使用的x86架構以及不同的作業系統

比如32位作業系統和64位作業系統對儲存的管理和儲存單元的讀寫都不盡相同,如果我們的**需要在不同的平台上執行該怎麼辦,我們不能每種架構和每種系統都開

發一套程式吧。此時我們需要定義一種通用的位元組對齊方式,不管什麼架構與系統都能能資料進行完整正確的讀寫。

(4)網路通訊問題:

在進行網路通訊的時候,如果是相同的平台間進行,則無需關心位元組問題,但是跨平台的通訊,由於不同架構和作業系統對儲存的管理不同,如果不採用傳送及接收方都

滿足的位元組對齊方式,將導致資料的錯亂甚至是程式的崩潰。

(5)位元組對齊解決的問題:

上面所說的問題,其實都是cpu讀寫是以儲存單元進行的,但是我們實際運用的型別的資料大小並非和儲存單元大小相同,所以儲存單元存在位元組填充的問題,我們的

構建的結構體等資料結構,不存在位元組填充,那麼上面的問題都不將存在,所以說,位元組對齊是一種契約,主要解決位元組填充問題。

(6)為什麼選擇8位元組對齊:

就目前而言,64位作業系統預設是8位元組對齊的,8位元組對齊能滿足各種計算架構和系統。

結構體內存布局

比如有如下結構體:

32位作業系統輸出:offset[a: 0, d:  4, c: 12] size: 16

64位作業系統輸出:offset[a: 0, d:  8, c: 16] size: 24

為何差別會這麼大,因為32為作業系統是4位元組對齊(乙個儲存單位為4位元組),64位作業系統位8位元組對齊(乙個儲存單元為8位元組)

如上結構體內存布局如下圖所示:

記憶體布局規則(32位系統4位元組為儲存單元為例):

(1)如果當前的儲存單元空間能不小於當前變數的大小,則儲存到該儲存空間,否則儲存到另乙個儲存空間。

(2)如果變數大小查過儲存單元,則分配多個儲存單元進行儲存。

(3)向後看齊,在乙個儲存單元中存在不同型別,則前面的成員向後補齊,比如存在相鄰兩個成員char和short,在儲存short成員的時候相對char偏移兩個位元組。

8位元組對齊規則

位元組對齊主要是消除系統的位元組填充,規則如下:

(1)結構體內不存在位元組填充。

(2)結構體大小為8位元組的整數倍。

在構建結構體時,注意以下事項:

(1)相同的型別盡量放在一塊

(2)小位元組型別盡量放在大位元組型別之前

(3)避免有填充位元組存在

(4)結構體大小為8的整數倍

8位元組檢測與對齊演算法實現

有時候我們需要一些工具來檢測8位元組是否對齊或者生成乙個對齊的結構體。

因為一般工具都選擇python實現,以下為python實現的8位元組檢測與實現的**(只列出檢測與對齊部分,實際運用中需要進行標頭檔案解析,提取結構體資訊。列舉長度同int,

結構體長度為  8,聯合體當結構體處理,檢測每乙個結構體,如果都是8位元組對齊,那該結構體即為8位元組對齊)

1 #!/usr/bin/python

2 #coding=utf-8

4 bitoffset = lambda x, align: (x+(align-1)) & ~(align-1)5

7 classstview(object):8

9 def __init__(self):10 self.name = none #結構體名

11 self.members = #結構體成員,stmemberview物件

14 classstmemberview(object):15

16 def __init__(self, name=none, type_=none, size=none, number=1):17 self.name = name #結構體成員名

18 self.type = type_ #結構體成員型別

19 self.size = size #結構體成員大小

20 self.number = number #結構體成員陣列大小

23 def check8bit(stview=stview()):24 """

25 8位元組檢測26 :param stview:27 :return:28 """

29 offset =030 for mem instview.members:31 offset2 =bitoffset(offset, int(mem.size))32 if offset2 !=offset:33 print "structural is not 8 bit aligned with . need bit before ".\34 format(stview.name, mem.name, offset2-offset)35 returnfalse36 else:37 offset += mem.number *int(mem.size)38 offset2 = bitoffset(offset, 8)39 if offset2 !=offset:40 print "structural is not 8 bit aligned with end. need bit before end". \41 format(stview.name, offset2 -offset)42 returnfalse43 returntrue44

46 def align8bit(stview=stview()):47 """

48 8位元組自動填充49 :param stview:50 :return:51 """

52 flag = index = offset =053 while index

59 else:60 offset += stview.members[index].number *int(stview.members[index].size)61 index += 1

62 offset2 = bitoffset(offset, 8)63 if offset2 !=offset:64 align_mem = stmemberview("filled_".format(flag), "char", 1, offset2 -offset)65 stview.members.insert(index + 1, align_mem)66 returntrue67

69 if __name__ == "__main__":70 st =stview()71 """

72 例如結構體:73 tt74 81 """

83 st.name = "tt"

89 check8bit(st)90

91 align8bit(st)92 for mem inst.members:93 print mem.name, mem.type, mem.size, mem.number

執行結構如下:

結構體位元組對齊

include pragma pack 2 struct t.pragma pack int main int argc,char argv 最後輸出的結果為 8。這個表示是按照2位元組來對齊資料,首先分配2位元組給成員變數i,分配完成後,還剩一位元組,zj add補0 沒法容納成員變數d,此時會再...

結構體位元組對齊

include pragma pack 2 struct t.pragma pack int main int argc,char argv 最後輸出的結果為 8。這個表示是按照2位元組來對齊資料,首先分配2位元組給成員變數i,分配完成後,還剩一位元組,zj add補0 沒法容納成員變數d,此時會再...

結構體位元組對齊

在用sizeof運算子求算某結構體所佔空間時,並不是簡單地將結構體中所有元素各自佔的空間相加,這裡涉及到記憶體位元組對齊的問題。從理論上講,對於任何 變數的訪問都可以從任何位址開始訪問,但是事實上不是如此,實際上訪問特定型別的變數只能在特定的位址訪問,這就需要各個變數在空間上按一定的規則排列,而不是...