結構體成員非對齊訪問所帶來的思考

2021-05-18 07:56:10 字數 2263 閱讀 4014

結構體成員非對齊訪問所帶來的思考

sailor_forever  sailing_9806#163.com

【摘要】本文介紹了記憶體訪問時為什麼需要對齊及不對齊時帶來的影響。接著介紹了如何改變對齊規則來保證cpu能夠訪問非對齊記憶體。最後介紹了結構體設計時需要注意的問題,如何調整成員順序或者填充特定單元來避免平台差異所帶來的潛在異常。

【關鍵字】x86 mips powerpc alignment exception 非對齊訪問 儲存器週期

1    問題的引子

在論壇上看到的乙個帖子,如下:

//標  題: 交叉編譯器導致sizeof結果不一致  

剛剛解決了乙個問題

乙個程式莫名其妙地就執行不了了

仔細檢查之後發現原來是乙個巨集裡面包含sizeof(某資料結構)

在4.2版本的arm-linux-gcc 下這個sizeof的結果是16

在3.4.3版本下結果是24

略有無語。。。開始怎麼也沒想到是這個問題,以為是**版本控制或者硬體出了問題

/首先明確一點,基於不同cpu甚至是相同的cpu但不同的編譯器版本

對結構體的對齊都可能不一樣,這就將導致結構體大小的差異

2    結構體為什麼需要對齊?

一是因為跨cpu通訊 需要保證雙方對資料的解析一致 這就要求有相同的對齊規則

二是因為 非對齊的資料 需要多個儲存器訪問週期才能取得所需要的資料 造成效率低下 當然這個低下 你從c語言級別是看不出來的 彙編指令級也看不出來 只能從儲存器的匯流排時序上看

所以編譯器一般會自動對齊  以空間換時間

三是因為 有些cpu不支援非對齊訪問 為什麼不支援 因為效率低 乾脆直接當異常處理得了

據我所知x86在硬體級別支援非對齊訪問 也就是說不對齊的問題 軟體無法感知

但mips 龍芯 sparc ppc arm等就不支援非對齊訪問 這時候會丟擲乙個異常

有些作業系統如linux會自動對異常進行糾正 保證得到正確的值

對程式設計師來說 你不會覺得有任何問題  但是對於os來說 那可是費了九牛二虎之力啊

3    如何改變結構體的對齊規則?

可以人為的改變對齊規則 但是不同的方法 控制的粒度是不一樣的

makefile可以控制整個工程的對齊規則

pragma pack(n)和pragma pack(n)配合可以控制此區間的對齊規則

__attribute((packed (n))可以控制特定的結構體的對齊規則

可見影響乙個結構體大小的因素太多了

是不是結構體對齊了就能保證程式沒有問題呢 顯然不是

是否對齊只是改變了資料的儲存方式 並不能改變cpu訪問資料的方式

對於不支援非對齊訪問的cpu 在半字位址訪問字仍然會造成異常

雖說os能夠處理這個異常 但是代價太大了 

這樣倒不如直接告訴編譯器 預設以非對齊的方式來訪問資料

這正式__attribute((packed (n))的功能 也是區別於其他改變對齊規則的機制

這個時候會編譯成多條指令來訪問__attribute((packed (n))修飾的資料

相對於os異常處理來說代價小了 但相對於對齊訪問來說 還是有代價

想想如果通篇都是這樣的資料  乙個字都得分成4個位元組來訪問 那效率是指數下降的

4    如何保證自動對齊?如何避免訪存失敗?如何提高訪存效率?

那麼我們怎麼樣才能保證我們定義的結構體不隨著平台及編譯器的版本而變化呢

合理調整成員的順序及人為的進行填充  保證已經對齊了

這樣不論什麼編譯器 結構體的大小都是固定的

因為是對齊的資料  無論cpu是否支援非對齊訪問 都不會產生異常

因為是對齊訪問 所以不會損失效率

唯一的代價就是浪費了一定人為填充的空間

但這一點空間效率的損失帶來的效益卻是無窮的

不光程式執行的效率提高了  程式跨平台的可移植性也強了  在任意的cpu上都有一致的表現

其實除了結構體會帶來非對齊訪問的問題,指標的強制轉換也是乙個潛在的不對齊的問題。因此應該避免強制進行指標轉換,而是讓編譯器以warning的形式告訴我們,這樣可以確認這個強制轉換是否有問題。

windows程式設計師永遠不需要為記憶體對齊問題操心費神

但他們太安樂了 可惜的是也享受不到異常帶來的刺激

這也正是嵌入式程式設計師的幸福所在  因為有問題 所以我們才會懂的更多

痛  但我們快樂著

乙個很有趣的帖子,問題雖小,但卻折**很多問題,直接看到凌晨三點多,還是很帶勁

結構體的對齊訪問

結構體的對齊訪問 1 結構體中元素的訪問其實本質還是用指標方式,結合這個元素在整個結構體中的偏移量和這個元素的型別來進行訪問的。2 每個元素實際佔的位元組數和自己本身的型別所佔的位元組數不一定完全一樣。譬如char c實際佔位元組數可能是1,也可能是 2,也可能是3,也可能是4 3 一般來說,我們用...

關於結構體的成員對齊與結構體整體對齊

大多數計算機體系結構中,對記憶體操作時按整字訪問才能達到最高效率,相當於是以空間換取時間,看似浪費了記憶體空間,但換來了訪問效率,先來說說三個概念 系統對齊值,自身對齊值,有效對齊值,三個概念的單位均為位元組,一開始概念不懂沒關係,可以對照後面的程式和記憶體分布圖來理解 1,系統對齊值 對於不同的作...

結構體成員對齊的問題

現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。1 現象 比如有些平台每次讀都是從偶位址開始...