程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 失落的C語言結構體封裝藝術(1)

失落的C語言結構體封裝藝術(1)

編輯:C++入門知識

Eric S. Raymond

目錄

1. 誰該閱讀這篇文章

2. 我為什麼寫這篇文章

3.對齊要求

4.填充

5.結構體對齊及填充

6.結構體重排序

7.難以處理的標量的情況

8.可讀性和緩存局部性

9.其他封裝的技術

10.工具

11.證明及例外

12.版本履歷

 1. 誰該閱讀這篇文章

本文是關於削減C語言程序內存占用空間的一項技術——為了減小內存大小而手工重新封裝C結構體聲明。你需要C語言的基本知識來讀懂本文。

如果你要為內存有限制的嵌入式系統、或者操作系統內核寫代碼,那麼你需要懂這項技術。如果你在處理極大的應用程序數據集,以至於你的程序常常達到內存的界限時,這項技術是有幫助的。在任何你真的真的需要關注將高速緩存行未命中降到最低的應用程序裡,懂得這項技術是很好的。

最後,理解該技術是一個通往其他深奧的C語言話題的入口。直到你掌握了它,你才成為一個高端的C程序員。直到你可以自己寫出這篇文檔並且可以理智地評論它,你才成為一位C語言大師。

2. 我為什麼寫這篇文章

本文之所以存在,是因為在2013年底,我發現我自己在大量使用一項C語言的優化技術,我早在二十多年前就已經學會了該技術,不過在那之後並沒怎麼使用過。

我需要減小一個程序的內存占用空間,它用了幾千——有時是幾十萬個——C結構體的實例。這個程序是cvs-fast-export,而問題在於處理巨大的代碼庫時,它曾因內存耗盡的錯誤而瀕臨崩潰。

在這類情況下,有好些辦法能極大地減少內存使用的,比如小心地重新安排結構體成員的順序之類的。這可以獲得巨大的收益——在我的事例中,我能夠減掉大約40%的工作區大小,使得程序能夠在不崩潰的情況下處理大得多的代碼庫。

當我解決這個問題,並且回想我所做的工作時,我開始發現,我在用的這個技術現今應被忘了大半了。一個網絡調查確認,C程序員好像已經不再談論該技術了,至少在搜索引擎可以看到的地方不談論了。有幾個維基百科條目觸及了這個話題,但是我發現沒人能全面涵蓋。

實際上這個現象也是有合理的理由的。計算機科學課程應當)引導人們避開細節的優化而去尋找更好的算法。機器資源價格的暴跌已經使得壓搾內存用量變 得不那麼必要了。而且,想當年,駭客們曾經學習如何使用該技術,使得他們在陌生的硬件架構上撞牆了——現在已經不太常見的經歷。

但是這項技術仍然在重要的場合有價值, 並且只要內存有限,就能永存。本文目的就是讓C程序員免於重新找尋這項技術,而讓他們可以集中精力在更重要的事情上。

3. 對齊要求Alignment Requirement)

要明白的第一件事是,在現代處理器上,你的C編譯器在內存裡對基本的C數據類型的存放方式是受約束的,為的是內存訪問更快。

在x86或者ARM處理器上,基本的C數據類型的儲存一般並不是起始於內存中的任意字節地址。而是,每種類型,除了字符型以外,都有對齊要求;字符 可以起始於任何字節地址,但是2字節的短整型必須起始於一個偶數地址,4字節整型或者浮點型必須起始於被4整除的地址,以及8字節長整型或者雙精度浮點型 必須起始於被8整除的地址。帶符號與不帶符號之間沒有差別。

這個的行話叫:在x86和ARM上,基本的C語言類型是自對齊self-aligned)的。指針,無論是32位4字節)亦或是64位8字節)也都是自對齊的。

自對齊使得訪問更快,因為它使得一條指令就完成對類型化數據的取和存操作。沒有對齊的約束,反過來,代碼最終可能會不得不跨越機器字的邊界做兩次或更多次訪問。字符是特殊的情況;無論在一個單機器字中的何處,存取的花費都是一樣的。那就是為什麼字符型沒有被建議對齊。

我說“在現代的處理器上”是因為,在一些舊的處理器上,強制讓你的C程序違反對齊約束比方說,將一個奇數的地址轉換成一個整型指針,並試圖使用 它)不僅會使你的代碼慢下來,還會造成非法指令的錯誤。比如在Sun的SPARC芯片上就曾經這麼干。實際上,只要夠決心並在處理器上設定正確e18) 的硬件標志位,你仍然可以在x86上觸發此錯誤。

此外,自對齊不是唯一的可能的規則。歷史上,一些處理器特別是那些缺少移位暫存器的)有更強的限制性規則。如果你做嵌入式系統,你也許會在跌倒在這些叢林陷阱中。注意,這是有可能的。

有時你可以通過編譯指示,強制讓你的編譯器不使用處理器正常的對齊規則,通常是#pragma pack。不要隨意使用,因為它會導致產生開銷更大、更慢的代碼。使用我在這裡描述的技術,通常你可以節省同樣或者幾乎同樣多的內存。

#pragma pack的唯一好處是,如果你不得不將你的C語言數據分布精確匹配到某些位級別的硬件或協議的需求,比如一個內存映射的硬件端口,要求違反正常的對齊才能奏效。如果你遇到那種情況,並且你還未理解我在這裡寫的這一切,你會有大麻煩的,我只能祝你好運了。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved