C語言重難點之內(nèi)存對齊和位段
一:結(jié)構體內(nèi)存對齊
(1)為什么要存在內(nèi)存對齊
平臺原因(移植原因): 不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些平臺只能在某些地址處取得某些特定類型的數(shù)據(jù),否則拋出硬件異常。
比如,當一個平臺要取一個整型數(shù)據(jù)時只能在地址為4的倍數(shù)的位置取得,那么這時就需要內(nèi)存對齊,否則無法訪問到該整型數(shù)據(jù)。
性能原因:
數(shù)據(jù)結(jié)構(尤其是棧)應該盡可能的在自然邊界上對齊。原因在于,為了訪問未對齊內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需一次。
核心思想就是:以空間換取時間
struct s1 { char c1; int i; char c2; }
由于c1占1個字節(jié),i占4個字節(jié),c2占1個字節(jié),所以計算機在讀取時候,會先讀取c1和i的3個字節(jié)(共四個字節(jié))、再讀取i的最后一個字節(jié)和c2。因此計算器不但需要進行兩次內(nèi)存讀取,并且還需要對i的數(shù)據(jù)進行拼接,無形中浪費了運行的時間。所以為了減少時間的浪費,就采用了內(nèi)存對齊的方式。
(2)結(jié)構體對齊規(guī)則
- 第一個成員在與結(jié)構體變量偏移量為0的地址處。(即結(jié)構體的首地址處,即對齊到0處)
- 其他成員變量要對齊到某個數(shù)字(對齊數(shù))的整數(shù)倍的地址處。
- 結(jié)構體的總大小為最大對齊數(shù)(每個成員變量都有一個對齊數(shù))的整數(shù)倍。
- 如果嵌套了結(jié)構體,嵌套的結(jié)構體對齊到自己的最大對齊數(shù)的整數(shù)倍處,結(jié)構體的整體大小就是所有最大對齊數(shù)(含嵌套結(jié)構體的對齊數(shù))的整數(shù)倍。
其中對齊數(shù)=編譯器默認的一個對齊數(shù)與該成員大小的較小值。vs中默認為8。Linux中默認值為4。
(3)結(jié)構體對齊演示
以下面的構體為例
struct S { double d; char c; int i; };
第一步:把結(jié)構體中每個成員變量的大小與編譯器的默認對齊數(shù)進行比較,取小的作為該成員的對齊數(shù)
第二步:從0位開始,畫出這些成員的位置,注意對齊到自己的對齊數(shù)
故為16個字節(jié)
(4)練習
//練習1 struct S1{ char c1; int i; char c2; }; printf("%d\n", printf(struct S1);//12 //練習2 struct S2 { char c1; char c2; int i; }; printf("%d\n", sizeof(struct S2));//8 //練習3 struct S3 { double d; char c; int i; }; printf("%d\n", sizeof(struct S3));//16 //練習4-結(jié)構體嵌套問題 struct S4 { char c1; struct S3 s3; double d; }; printf("%d\n", sizeof(struct S4));//32
二:位段
(1)什么是位段
“節(jié)省空間”這四個字可以直截了當?shù)狞c名位段的作用。
在結(jié)構體設計中,我們一般用int
來存年齡這樣的數(shù)據(jù),但是年齡這個東西再大也不會達到幾百幾千,也就是它的范圍一般是1-100,反應在整形數(shù)據(jù)的內(nèi)存上,使用的可能就是32個比特位中的個別幾個,也就說剩余的很多比特位就是根本不會用到的,而如果明知道這樣,還要不管三七二十一直接拋出一個整形,四個字節(jié),32個比特位存儲這么小的數(shù),未免顯的有點浪費了。所以正式鑒于此,位段就能合理的進行內(nèi)存設計
(2)位段怎么寫
位段的基本格式如下,和結(jié)構體十分相似,其內(nèi)部的數(shù)據(jù)類型一般要求是一致的
(3)位段結(jié)構體對齊怎么算
上述這個結(jié)構體所占空間大小為八個字節(jié),在實際分配時,會一上來先分配四個字節(jié),其中a,b,c占據(jù)2+5+10共17個比特位,剩余d需要30個比特位存儲但是不夠,所以再分配四個字節(jié),拿出其中30個比特位存儲??梢钥闯鱿啾戎氨┝Φ闹苯?6個字節(jié),現(xiàn)在的8個字節(jié)大大的節(jié)省了空間。
再比如下面位段
struct A { unsigned a : 19; unsigned b : 11; unsigned c : 4; unsigned d : 29; char index; };
其中a和b共占據(jù)4個字節(jié),c和d占據(jù)八個字節(jié),index對齊對齊1個字節(jié),最終就是16
位段的跨平臺問題
- int 位段被當成有符號數(shù)還是無符號數(shù)是不確定的。
- 位段中最大位的數(shù)目不能確定。(16位機器最大16,32位機器最大32,寫成27,在16位機
- 器會出問題。
- 位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標準尚未定義。
- 當一個結(jié)構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是舍棄剩余的位還是利用,這是不確定的。
到此這篇關于C語言重難點之內(nèi)存對齊和位段的文章就介紹到這了,更多相關C語言 內(nèi)存對齊和位段內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++?Boost?CircularBuffer算法超詳細精講
Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱2022-11-11Visual?Studio?2022?安裝低版本?.Net?Framework的圖文教程
這篇文章主要介紹了Visual?Studio?2022?如何安裝低版本的?.Net?Framework,首先打開?Visual?Studio?Installer?可以看到vs2022?只支持安裝4.6及以上的版本,那么該如何安裝4.6以下的版本,下面將詳細介紹,需要的朋友可以參考下2022-09-09C語言深入探究自定義類型之結(jié)構體與枚舉及聯(lián)合
今天我們來學習一下自定義類型,自定義類型包括結(jié)構體、枚舉、聯(lián)合體,小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考2022-05-05va_list(),va_start(),va_arg(),va_end() 詳細解析
這些宏定義在stdarg.h中,所以用到可變參數(shù)的程序應該包含這個頭文件.下面我們寫一個簡單的可變參數(shù)的函數(shù),該函數(shù)至少有一個整數(shù)參數(shù),第二個參數(shù)也是整數(shù),是可選的.函數(shù)只是打印這兩個參數(shù)的值2013-09-09用C語言舉例講解數(shù)據(jù)結(jié)構中的算法復雜度結(jié)與順序表
這篇文章主要介紹了講解數(shù)據(jù)結(jié)構中的算法復雜度結(jié)與順序表的C語言版示例,包括對時間復雜度和空間復雜度等概念的簡單講解,需要的朋友可以參考下2016-02-02C語言 深入解讀數(shù)據(jù)結(jié)構之堆的實現(xiàn)
堆就是用數(shù)組實現(xiàn)的二叉樹,所以它沒有使用父指針或者子指針。堆根據(jù)“堆屬性”來排序,“堆屬性”決定了樹中節(jié)點的位置2021-11-11