C語言好難 結構體的記憶體分配

2021-07-23 13:34:28 字數 3820 閱讀 7678

結構體的記憶體分配,我個人是覺得比較蛋疼的,它有乙個需要遵循的原則,位址對齊,也有人稱為記憶體對齊,叫法沒關係,反正我只是「拿來」,會用就行。

好了,先有這麼乙個概念,什麼是記憶體對齊,先丟一邊。……~(~o ̄▽ ̄)~o 。。。滾來滾去……o~(_△_o~) ~。。

設char占用1個位元組,int占用4個位元組。

那麼問題1

struct a

char a;

int a0;

}ma;

char a1;

a1 = sizeof(ma);

下面是在keil中**的結果

?_?,為什麼是8???,不是5?

是的,不是5,在編譯器裡面,為了非連續變數取得的位址能整除於結構體的基位址(結構體的分配的基位址也需要滿足可以整除於所占用的記憶體的最大資料型別的位元組數,這句話好繞啊_(:3」∠)_),偏移位址需要對齊。就是說在給變數分配的時候,如果不是連續定義的變數,直接分配乙個最大的記憶體空間,即使我給a0變數定義的是乙個char型變數,編譯器依舊給其分配了4個位元組。

關於偏移位址對齊的說法,我個人傾向於同意的說法是,在給結構體分配記憶體空間時,如果變數位址不連續(注意這句話,很重要),編譯器寧可取結構體中記憶體占用最大的元素為每個變數分配記憶體,不夠的空間予以補足,只是呼叫的時候不用而已。

下面結合*.map檔案分析一下各個變數的記憶體分配

ma                                       0x2000002c   data           8  main.o(.data)

a2                                       0x20000034   data           1  main.o(.data)

a3                                       0x20000035   data           1  main.o(.data)

a4                                       0x20000036   data           1  main.o(.data)

a5                                       0x20000038   data           4  main.o(.data)

上面是各個變數的位址分配,我沒有在*. map檔案中找到 ma.a0 和 ma.a1 的變數位址,(~ ̄▽ ̄~) 那又怎樣,不就繞個彎嘛。

在上圖中我通過乙個指標變數將ma.a1的位址取了出來,然後執行到紅點處停止,結合*.map檔案分析,a2位址為0x20000034,ma位址為0x2000002c ,兩者相減為8,就是ma的記憶體分配大小,然後我之前說過,結構體中變數的記憶體的分配是直接每個變數分配乙個所有元素中最大的記憶體占用元素的,也就是說ma .a0也占用了4個位元組。

現在,驗證方法就是用ma.a1的位址減去ma的位址。

即   0x20000030 - 0x2000002c = 4;

結果出來了,a0變數占用了4個位元組的記憶體,還有兩個位元組的記憶體空間去**了?直接遮蔽了唄。  

下面繼續驗證我的說法,編譯器給結構體分配記憶體是,直接分配所含成員中,資料型別最大那個的占用位元組數乘以元素個數。

這張驗證了,結構體可以分配1個位元組,而結構體成員裡面就乙個char型變數,位元組數最大占用為1。

看了這麼多,下面來個題目。

struct a

ma;char a2,a3,a4;

int* a5;

int main()

設ma位址0x2000002c,請問,a2、a3、a4、a5的值各為多少?

嘿嘿,是8,就是說,如果是連續的char型變數,編譯器依舊會給它分配兩個位元組的記憶體空間。

把上題目改一下哈

struct a

ma;char a2,a3,a4;

int* a5;

int main()

設ma位址為0x2000010c,請問,a2、a3、a4、a5的值各為多少?

這次的記憶體位址分配變更了,map檔案如下

a2                                       0x2000002c   data           1  main.o(.data)

a3                                       0x2000002d   data           1  main.o(.data)

a4                                       0x2000002e   data           1  main.o(.data)

a5                                       0x20000030   data           4  main.o(.data)

__stdout                                 0x20000038   data           4  stdout.o(.data)

uart                                     0x2000003c   data         208  main.o(.bss)

ma                                       0x2000010c   data          12  main.o(.bss)

從上面的**分析,ma.a0依舊是占用4個記憶體位元組,ma.b也是4個。

為了使驗證更使人信服,我增加了兩個測試,增加位定義。

如圖,即使我只宣告了乙個位,依舊分配了4個位元組。

*.map檔案中的位址分配如下

ma                                       0x2000002c   data           2  main.o(.data)

a2                                       0x2000002e   data           1  main.o(.data)

a3                                       0x2000002f   data           1  main.o(.data)

a4                                       0x20000030   data           1  main.o(.data)

a5                                       0x20000034   data           4  main.o(.data)

就是說,如果連續定義8個位,只占用了兩個位元組

綜上所述,如果可能的話,在編寫c語言的時候,盡量將資料型別相同的變數連續排在一起。

寫完了,看懂了嗎,不懂?我就喜歡你懵逼的樣子,<( ̄︶ ̄)> 。

寫於2023年10月10日凌晨  深圳

C語言結構體的記憶體分配

原則一 結構體中元素按照定義順序存放到記憶體中,但並不是緊密排列。從結構體儲存的首位址開始 每乙個元素存入記憶體中時,它都會認為記憶體是以自己的寬度來劃分空間的,因此元素存放的位置一定會在自己大小的整數倍上開始。原則二 在原則一的基礎上,檢查計算出的儲存單元是否為所有元素中最寬的元素長度的整數倍。若...

c 結構體,既記憶體分配

說明結構變數有以下三種方法。以上面定義的stu為例來加以說明。1 先定義結構,再說明結構變數。如 struct stu struct stu boy1,boy2 說明了兩個變數boy1和boy2為stu結構型別。也可以用巨集定義使乙個符號常量來表示乙個結構型別。例如 define stu struc...

結構體的記憶體分配

記憶體大小和系統有關,如32位系統和64位系統,同一資料型別,記憶體分配大小不一 假設這台機器是sizeof char 1 sizeof int 4 sizeof double 8 列舉型別只為最寬的資料分配記憶體,在不同的時候,用的是同一塊記憶體 在預設情況下,規定各成員變數的起始位址相對於結構的...