一篇文章帶你了解C語(yǔ)言內(nèi)存對(duì)齊公式
一、前言
每一個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))。GCC中默認(rèn)#program pack(4),即4個(gè)字節(jié)的內(nèi)存對(duì)齊。Keil也是采用4字節(jié)對(duì)齊的。也可以通過(guò)預(yù)編譯命令#pragma pack(n),n = 1,2,4,8,16來(lái)改變這一系數(shù),一般情況下盡量使用自然對(duì)齊系數(shù),不要修改它。
STM32單片機(jī)上各個(gè)變量占用的字節(jié)數(shù):


二、公式
公式一、結(jié)構(gòu)體變量里,成員的起始地址必須滿足 : 起始地址 % 成員的字節(jié)數(shù)(sizeof值)= 0 (說(shuō)白了就是能整除)
公式二、結(jié)構(gòu)體變量的總字節(jié)數(shù)必須滿足:總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0 (說(shuō)白了就是能整除)
2.1、例子一
struct te_a{
/* 公式一 */
char a; /* a的起始地址0x00,然后用公式一計(jì)算:0x00 % 1(char為1個(gè)字節(jié)) = 0,所以成員a占用了內(nèi)存0x00 */
int b; /* b的起始地址0x01 % 4(int為4個(gè)字節(jié))不等于0,那么再計(jì)算0x02%4還是不等于0,直到0x04 % 4 = 0 ,所以成員b占用了內(nèi)存0x04 ~ 0x07 */
char c; /* 成員b的結(jié)尾地址是0x07,所以成員c從0x08開始計(jì)算,那么計(jì)算0x08 % 1 = 0 , 所以成員c占用了內(nèi)存0x08 */
}Test1;
OK,經(jīng)過(guò)公式一的運(yùn)算后,結(jié)構(gòu)體里成員的分布如下:

經(jīng)過(guò)公式一的計(jì)算后,結(jié)構(gòu)體變量Test1的大小是9個(gè)字節(jié)。內(nèi)存對(duì)齊的計(jì)算還沒有結(jié)束,接著使用公式二計(jì)算:
結(jié)構(gòu)體變量的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0 , 在結(jié)構(gòu)體變量Test1里,最大的成員是b,b的大小是4個(gè)字節(jié)。那么,當(dāng)前的結(jié)構(gòu)體變量大小9字節(jié) % 4字節(jié) 等于 0 。當(dāng)結(jié)構(gòu)體變量大小為12字節(jié) % 4字節(jié) = 0,所以最終結(jié)構(gòu)體變量Test1占用的內(nèi)存字節(jié)數(shù)是12,其內(nèi)存的分布如下:

以上的都是根據(jù)公式計(jì)算出來(lái)的結(jié)果,那實(shí)際在單片機(jī)里是不是這樣呢?把代碼下載到STM32單片機(jī)里,進(jìn)入DEBUG模式看看。


從以下的內(nèi)存分布看來(lái),公式一與公式二的計(jì)算沒有問(wèn)題。

2.2、例子二
struct te_a{
/* 公式一 */
int a; /* a的起始地址是0x00,然后根據(jù)公式一計(jì)算0x00 % 4 = 0 ,那么成員a占用的內(nèi)存是0x00 ~ 0x03 */
float b; /* b的起始地址是0x04, 然后根據(jù)公式一計(jì)算0x04 % 4 = 0 ,那么成員b占用的內(nèi)存是0x04 ~ 0x07 */
char c; /* c的起始地址是0x08, 然后根據(jù)公式一計(jì)算0x08 % 1 = 0 ,那么成員c占用的內(nèi)存是0x08 */
}Test1;
OK,經(jīng)過(guò)公式一的運(yùn)算后,結(jié)構(gòu)體里成員應(yīng)該占用9個(gè)字節(jié)的內(nèi)存,內(nèi)存的分布如下:

接著根據(jù)公式二的運(yùn)算,結(jié)構(gòu)體的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0, 可以輕松得出結(jié)構(gòu)體的總字節(jié)數(shù) = 12時(shí),滿足12 % 4 = 0。所以經(jīng)過(guò)公式二的計(jì)算后,內(nèi)存分布如下:

把代碼燒錄到STM32,進(jìn)入Debug模式看看。



2.3、例子三
struct te_a{
/* 公式一 */
int a; /* a的起始地址是0x00,然后根據(jù)公式一計(jì)算0x00 % 4 = 0 ,那么成員a占用的內(nèi)存是0x00 ~ 0x03 */
float b; /* b的起始地址是0x04, 然后根據(jù)公式一計(jì)算0x04 % 4 = 0 ,那么成員b占用的內(nèi)存是0x04 ~ 0x07 */
double c; /* c的起始地址是0x08, 然后根據(jù)公式一計(jì)算0x08 % 8 = 0 ,那么成員c占用的內(nèi)存是0x08 ~ 0x0F */
}Test1;
OK,經(jīng)過(guò)公式一的運(yùn)算后,結(jié)構(gòu)體里成員應(yīng)該占用16個(gè)字節(jié)的內(nèi)存,內(nèi)存的分布如下:

接著根據(jù)公式二的運(yùn)算,結(jié)構(gòu)體的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0, 那么16 % 8 = 0,運(yùn)氣非常好,公式二不用補(bǔ)位就能讓公式二成立。所以經(jīng)過(guò)公式二的運(yùn)算后,內(nèi)存還是一樣的:

把代碼燒錄到STM32,進(jìn)入Debug模式看看。



總結(jié)
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- C語(yǔ)言結(jié)構(gòu)體內(nèi)存對(duì)齊詳解
- C語(yǔ)言熱門考點(diǎn)結(jié)構(gòu)體與內(nèi)存對(duì)齊詳解
- C語(yǔ)言中結(jié)構(gòu)體與內(nèi)存對(duì)齊實(shí)例解析
- C語(yǔ)言中結(jié)構(gòu)體、聯(lián)合體的成員內(nèi)存對(duì)齊情況
- 一篇文章帶你了解C語(yǔ)言內(nèi)存對(duì)齊解決的問(wèn)題
- 一篇文章帶你了解C語(yǔ)言內(nèi)存對(duì)齊
- C語(yǔ)言重難點(diǎn)之內(nèi)存對(duì)齊和位段
- C語(yǔ)言內(nèi)存對(duì)齊實(shí)例詳解
- 深入理解C語(yǔ)言內(nèi)存對(duì)齊
- C語(yǔ)言結(jié)構(gòu)體中內(nèi)存對(duì)齊的問(wèn)題理解
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之二分法查找詳解
二分查找算法是在有序數(shù)組中用到的較為頻繁的一種算法,在未接觸二分查找算法時(shí),最通用的一種做法是,對(duì)數(shù)組進(jìn)行遍歷,跟每個(gè)元素進(jìn)行比較,其時(shí)間為O(n),但二分查找算法更優(yōu)2022-02-02
基于Windows API實(shí)現(xiàn)遍歷所有文件并刪除的方法
這篇文章主要介紹了基于Windows API實(shí)現(xiàn)遍歷所有文件并刪除的方法,是win32應(yīng)用程序的一個(gè)比較典型的文件操作應(yīng)用技巧,需要的朋友可以參考下2015-04-04

