C语言程序设计 | 结构体内存对齐,位段
在我們學習結構體時,可能會碰到幾個難以理解的問題,一個是內存對齊,一個是位段。所以我想分享一下我對這兩個問題的理解,來幫助大家更好的學習這兩個知識點。
內存對齊
struct {char i;char k; int j; }s1;struct {char i;int j;char k; }s2;int main() {printf("%d\n", sizeof(s1));printf("%d\n", sizeof(s2));return 0; }上面的兩個結構體,看上去是完全一樣的,只有聲明變量時的順序不一樣, 那么它們的大小一樣嗎?
運行后我們發(fā)現(xiàn),它們兩個的大小竟然不同,而且如果我們將它們每一個的大小相加起來,得到的也應該是6,不是上面的兩個值,那么這是因為什么呢?
這時,就牽扯到了一個叫做內存對齊的東西。
對齊數(shù) = 編譯器默認的一個對齊數(shù)與該成員大小的較小值
. vs的默認值為8,linux默認值為4(32位系統(tǒng)下由于數(shù)據(jù)總線只有32位,每次只能讀取4個字節(jié))
光看文字的話很難看懂,所以下面我會畫幾幅圖來描述一下內存對齊是如何運作的。
struct {char i;char k; int j; }s1;
因為第一個i與第二個j是相同類型,所以不存在偏移,k所占據(jù)的字節(jié)數(shù)比j大,所以偏移量為默認對齊數(shù)和K的大小的最小值,所以需要偏移到四個字節(jié),所以總共占了八個字節(jié)的大小
看完上面的幾個圖解,我們了解到如果要合理運用空間,就應該把占用空間較小的成員盡量集中到一起。
那么,問題來了,為什么要有內存對齊呢?
在我們能百度到的大部分資料上,都是這樣說的:
看文字的話,如果你還不懂,那我再來畫一幅圖
對于沒對齊過的,我們如果想讀取這個k,因為我們每次讀取四個字節(jié),所以第一次讀取的時候只讀取到了k的前三個字節(jié),第二次才能讀取到k的第四個字節(jié),然后將其進行重組,才能得到這個k。如果是對齊過的,我們就可以一次性讀取,雖然使用的空間變多了,但是速度也快了很多。
所以內存對齊的意義就是用空間來換取時間,而空間的價格較為低廉,所以內存對齊的性價比是十分高的。
對齊數(shù)的修改
當然,系統(tǒng)默認的對齊數(shù)是不能適用于所有情況下的,所以我們可以修改對齊數(shù)來適用于我們所處的情景。
我們可以適用一個預處理指令來修改默認的對齊數(shù) # pragma pack(x), 這個x就填入我們想修改的數(shù)值
如果我們想要只在一段使用這個對齊數(shù),而在下一段恢復的話,可以這樣使用
位段
講完了內存對齊,下一個就來講講這個位段。
什么是位段
位段的聲明和結構體是類似的,僅僅存在兩個地方的不同:
例如:
struct {int a : 1;int b : 3;int c : 5;int d : 31; }s3;那么,它的大小是多少呢?
為什么會是8呢?
因為一個整形是4個字節(jié),而4個字節(jié)有32個比特位,前三個我們分別給的是1,3,5,加起來總共是9,沒有達到32個比特位,而第四個占了31個,前三個已經(jīng)無法在存放這個31,所以這個31單獨存放在下一段空間中。總共占了兩個整形的空間,所以是2* 4,八個字節(jié)。
位段的內存分配
對于這個位段,空間是如何開辟的呢?
因為一個字符型占據(jù)一個字節(jié),而一個字節(jié)有八個比特位,所以我們需要先知道它們的二進制值
所有的二進制值我都寫出來了,同時用框框框起來的是因為二進制數(shù)的位數(shù)大于我們的位段數(shù),所以我們需要進行截斷
這就是位段的存儲方式。
位段的跨平臺問題
上面的最后一點提到過對于跨平臺的程序應該避免使用位段,這是為什么呢?
跟結構相比,位段可以達到相同的效果,雖然可以很好的節(jié)省空間,但是存在著跨平臺的問題。
總結
以上是生活随笔為你收集整理的C语言程序设计 | 结构体内存对齐,位段的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言程序设计 | 模拟实现内存操作函数
- 下一篇: C语言程序设计 | 结构体,枚举,联合