日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

C语言程序设计 | 结构体内存对齐,位段

發布時間:2024/4/11 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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; }

上面的兩個結構體,看上去是完全一樣的,只有聲明變量時的順序不一樣, 那么它們的大小一樣嗎?

運行后我們發現,它們兩個的大小竟然不同,而且如果我們將它們每一個的大小相加起來,得到的也應該是6,不是上面的兩個值,那么這是因為什么呢?
這時,就牽扯到了一個叫做內存對齊的東西。

  • 第一個成員在與結構體變量偏移量為0的地址處。
  • 其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。
  • 對齊數 = 編譯器默認的一個對齊數與該成員大小的較小值

    . vs的默認值為8,linux默認值為4(32位系統下由于數據總線只有32位,每次只能讀取4個字節)

  • 結構體總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍。
  • 如果嵌套了結構體的情況,嵌套的結構體對齊到在自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍
  • 光看文字的話很難看懂,所以下面我會畫幾幅圖來描述一下內存對齊是如何運作的。

    struct {char i;char k; int j; }s1;


    因為第一個i與第二個j是相同類型,所以不存在偏移,k所占據的字節數比j大,所以偏移量為默認對齊數和K的大小的最小值,所以需要偏移到四個字節,所以總共占了八個字節的大小

    struct {char i;int j;char k; }s2;

    看完上面的幾個圖解,我們了解到如果要合理運用空間,就應該把占用空間較小的成員盡量集中到一起。

    那么,問題來了,為什么要有內存對齊呢?

    在我們能百度到的大部分資料上,都是這樣說的:

  • 平臺原因:不是所有的硬件平臺都能訪問任意地址上的任意數據的,某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
  • 性能原因:數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問,而對齊的內存訪問僅僅需要一次。(為對齊需要讀取多個總線周期)
  • 看文字的話,如果你還不懂,那我再來畫一幅圖

    對于沒對齊過的,我們如果想讀取這個k,因為我們每次讀取四個字節,所以第一次讀取的時候只讀取到了k的前三個字節,第二次才能讀取到k的第四個字節,然后將其進行重組,才能得到這個k。如果是對齊過的,我們就可以一次性讀取,雖然使用的空間變多了,但是速度也快了很多。

    所以內存對齊的意義就是用空間來換取時間,而空間的價格較為低廉,所以內存對齊的性價比是十分高的。

    對齊數的修改

    當然,系統默認的對齊數是不能適用于所有情況下的,所以我們可以修改對齊數來適用于我們所處的情景。

    我們可以適用一個預處理指令來修改默認的對齊數 # pragma pack(x), 這個x就填入我們想修改的數值


    如果我們想要只在一段使用這個對齊數,而在下一段恢復的話,可以這樣使用


    位段

    講完了內存對齊,下一個就來講講這個位段。

    什么是位段

    位段的聲明和結構體是類似的,僅僅存在兩個地方的不同:

  • 位段的成員必須是int , unsigned int ,signed int, char
  • 位段的成員名后邊有一個冒號和一個數字
  • 例如:

    struct {int a : 1;int b : 3;int c : 5;int d : 31; }s3;

    那么,它的大小是多少呢?
    為什么會是8呢?
    因為一個整形是4個字節,而4個字節有32個比特位,前三個我們分別給的是1,3,5,加起來總共是9,沒有達到32個比特位,而第四個占了31個,前三個已經無法在存放這個31,所以這個31單獨存放在下一段空間中。總共占了兩個整形的空間,所以是2* 4,八個字節。

    位段的內存分配

  • 位段的成員可以是int,unsigned int ,signed int, char類型
  • 位段的空間上是按照需要以四個字節(int)或者一個字節(char)的方式來開辟的。
  • 位段設計很多不確定因素,位段是不跨平臺的,所以可移植的程序應該避免使用位段

  • 對于這個位段,空間是如何開辟的呢?
    因為一個字符型占據一個字節,而一個字節有八個比特位,所以我們需要先知道它們的二進制值

    所有的二進制值我都寫出來了,同時用框框框起來的是因為二進制數的位數大于我們的位段數,所以我們需要進行截斷

    這就是位段的存儲方式。

    位段的跨平臺問題

    上面的最后一點提到過對于跨平臺的程序應該避免使用位段,這是為什么呢?

  • in位段被當成有符號的還是無符號數是不確定的。
  • 位段中最大位的數目不能確定(16位機器最大16,32位機器最大32,寫成27,在16位機器會出現問題)
  • 位段中的成員在內存中從左向右分配,還是從右向左分配標準尚未定義(這個就是我在上個月講的那個大小端的問題)
  • 當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是舍棄剩余的位還是利用,這是不確定的
  • 跟結構相比,位段可以達到相同的效果,雖然可以很好的節省空間,但是存在著跨平臺的問題。

    總結

    以上是生活随笔為你收集整理的C语言程序设计 | 结构体内存对齐,位段的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。