一篇文章帶你了解C語言內(nèi)存對齊公式
一、前言
每一個特定平臺上的編譯器都有自己的默認(rèn)“對齊系數(shù)”(也叫對齊模數(shù))。GCC中默認(rèn)#program pack(4),即4個字節(jié)的內(nèi)存對齊。Keil也是采用4字節(jié)對齊的。也可以通過預(yù)編譯命令#pragma pack(n),n = 1,2,4,8,16來改變這一系數(shù),一般情況下盡量使用自然對齊系數(shù),不要修改它。
STM32單片機(jī)上各個變量占用的字節(jié)數(shù):
二、公式
公式一、結(jié)構(gòu)體變量里,成員的起始地址必須滿足 : 起始地址 % 成員的字節(jié)數(shù)(sizeof值)= 0 (說白了就是能整除)
公式二、結(jié)構(gòu)體變量的總字節(jié)數(shù)必須滿足:總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0 (說白了就是能整除)
2.1、例子一
struct te_a{ /* 公式一 */ char a; /* a的起始地址0x00,然后用公式一計算:0x00 % 1(char為1個字節(jié)) = 0,所以成員a占用了內(nèi)存0x00 */ int b; /* b的起始地址0x01 % 4(int為4個字節(jié))不等于0,那么再計算0x02%4還是不等于0,直到0x04 % 4 = 0 ,所以成員b占用了內(nèi)存0x04 ~ 0x07 */ char c; /* 成員b的結(jié)尾地址是0x07,所以成員c從0x08開始計算,那么計算0x08 % 1 = 0 , 所以成員c占用了內(nèi)存0x08 */ }Test1;
OK,經(jīng)過公式一的運(yùn)算后,結(jié)構(gòu)體里成員的分布如下:
經(jīng)過公式一的計算后,結(jié)構(gòu)體變量Test1的大小是9個字節(jié)。內(nèi)存對齊的計算還沒有結(jié)束,接著使用公式二計算:
結(jié)構(gòu)體變量的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0 , 在結(jié)構(gòu)體變量Test1里,最大的成員是b,b的大小是4個字節(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ù)公式計算出來的結(jié)果,那實際在單片機(jī)里是不是這樣呢?把代碼下載到STM32單片機(jī)里,進(jìn)入DEBUG模式看看。
從以下的內(nèi)存分布看來,公式一與公式二的計算沒有問題。
2.2、例子二
struct te_a{ /* 公式一 */ int a; /* a的起始地址是0x00,然后根據(jù)公式一計算0x00 % 4 = 0 ,那么成員a占用的內(nèi)存是0x00 ~ 0x03 */ float b; /* b的起始地址是0x04, 然后根據(jù)公式一計算0x04 % 4 = 0 ,那么成員b占用的內(nèi)存是0x04 ~ 0x07 */ char c; /* c的起始地址是0x08, 然后根據(jù)公式一計算0x08 % 1 = 0 ,那么成員c占用的內(nèi)存是0x08 */ }Test1;
OK,經(jīng)過公式一的運(yùn)算后,結(jié)構(gòu)體里成員應(yīng)該占用9個字節(jié)的內(nèi)存,內(nèi)存的分布如下:
接著根據(jù)公式二的運(yùn)算,結(jié)構(gòu)體的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0, 可以輕松得出結(jié)構(gòu)體的總字節(jié)數(shù) = 12時,滿足12 % 4 = 0。所以經(jīng)過公式二的計算后,內(nèi)存分布如下:
把代碼燒錄到STM32,進(jìn)入Debug模式看看。
2.3、例子三
struct te_a{ /* 公式一 */ int a; /* a的起始地址是0x00,然后根據(jù)公式一計算0x00 % 4 = 0 ,那么成員a占用的內(nèi)存是0x00 ~ 0x03 */ float b; /* b的起始地址是0x04, 然后根據(jù)公式一計算0x04 % 4 = 0 ,那么成員b占用的內(nèi)存是0x04 ~ 0x07 */ double c; /* c的起始地址是0x08, 然后根據(jù)公式一計算0x08 % 8 = 0 ,那么成員c占用的內(nèi)存是0x08 ~ 0x0F */ }Test1;
OK,經(jīng)過公式一的運(yùn)算后,結(jié)構(gòu)體里成員應(yīng)該占用16個字節(jié)的內(nèi)存,內(nèi)存的分布如下:
接著根據(jù)公式二的運(yùn)算,結(jié)構(gòu)體的總字節(jié)數(shù) % 最大的成員字節(jié)數(shù) = 0, 那么16 % 8 = 0,運(yùn)氣非常好,公式二不用補(bǔ)位就能讓公式二成立。所以經(jīng)過公式二的運(yùn)算后,內(nèi)存還是一樣的:
把代碼燒錄到STM32,進(jìn)入Debug模式看看。
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++?Boost?StringAlgorithms超詳細(xì)講解
Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱2022-11-11C++編寫DLL動態(tài)鏈接庫的步驟與實現(xiàn)方法
這篇文章主要介紹了C++編寫DLL動態(tài)鏈接庫的步驟與實現(xiàn)方法,結(jié)合實例形式分析了C++導(dǎo)出類文件及生成與調(diào)用DLL動態(tài)連接庫的相關(guān)操作技巧,需要的朋友可以參考下2016-08-08