最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C語言如何計算結(jié)構(gòu)體大小(結(jié)構(gòu)體的內(nèi)存對齊)

 更新時間:2023年07月21日 10:10:18   作者:可涵不會debug  
結(jié)構(gòu)體的內(nèi)存對齊是有關(guān)結(jié)構(gòu)體內(nèi)容的很重要一個知識點,主要考察方式是計算結(jié)構(gòu)體的字節(jié)大小,所以本文就給大家詳細(xì)介紹一下C語言如何計算結(jié)構(gòu)體大小,文中的代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

引言:

當(dāng)我們對計算結(jié)構(gòu)體一無所知,我們不妨自己思索如何計算,是不是直接計算結(jié)構(gòu)體成員變量占用內(nèi)存的大小呢?

那我們先舉個例子

struct s1
{
	int i;
	char a;
	char b;
};
struct s2
{
	char a;
	int i;
	char b;
};
int main()
{
	printf("%d\n", sizeof(struct s1));
	printf("%d\n", sizeof(struct s2));
	return 0;
}

觀察發(fā)現(xiàn)結(jié)構(gòu)體的大小計算跟我們想的很不一樣。

不應(yīng)該是兩個char類型,一個int類型,2*1+4答案不應(yīng)該是6嗎?

上面兩個結(jié)構(gòu)體內(nèi)容是一樣的,只有順序不一樣,為何計算結(jié)果不一樣呢?

我們就帶著以上的疑問去探索!

一、計算偏移量

我們要研究明白結(jié)構(gòu)體的成員列表在內(nèi)存中到底是如何存儲的,首先要知道結(jié)構(gòu)體的各個成員變量在內(nèi)存中相較于起始位置的偏移量。這時候要引用到offsetof,這個宏可以計算結(jié)構(gòu)體成員相較于結(jié)構(gòu)體起始位置的偏移量。

使用宏offsetof

 如何使用宏offsetof?

首先有頭文件:#include<stddef.h>

參數(shù)是類型,和成員名,返回值就是結(jié)構(gòu)體成員相較于結(jié)構(gòu)體起始位置的偏移量。

我們先試著打印下s2各個成員關(guān)于結(jié)構(gòu)體起始位置的偏移量。

發(fā)現(xiàn)結(jié)果是0、4、8,我們可以畫一張內(nèi)存圖進(jìn)行理解。

如圖所示,根據(jù)offsetof我們可以得到這樣的內(nèi)存存儲模式,但是這樣一共也就9個字節(jié),后面的3個字節(jié)從何而來?中間多出來的3個字節(jié)又從何而來?

我們繼續(xù)探索。

結(jié)構(gòu)體到底如何計算?

二、結(jié)構(gòu)體的對齊規(guī)則

我們經(jīng)過上面的分析,發(fā)現(xiàn)結(jié)構(gòu)體成員不是按照順序在內(nèi)存中連續(xù)存放的,而是有一定的對齊規(guī)則,接下來我們就研究結(jié)構(gòu)體的內(nèi)存規(guī)則。

  • 結(jié)構(gòu)體的第一個成員永遠(yuǎn)放在相較于結(jié)構(gòu)體變量的起始未知的偏移量為0的位置
  • 從第二個成員開始,往后的每個成員都要對齊到某個對齊數(shù)的整數(shù)倍處。(對齊數(shù):結(jié)構(gòu)體成員自身大小和默認(rèn)對齊數(shù)的較小值)VS上默認(rèn)對齊數(shù)是8,gcc沒有默認(rèn)對齊數(shù),對齊數(shù)就是變量本身的大小。
  • 結(jié)構(gòu)體的總大小,必須是最大對齊數(shù)的整數(shù)倍,最大對齊數(shù)是:所有成員的對齊數(shù)中最大的值
  • 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對齊到自己的最大對齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對齊數(shù)(含嵌套結(jié)構(gòu)體的對齊數(shù))的整數(shù)倍。

三、總結(jié)計算方法

我們首先要知道結(jié)構(gòu)體變量成員的自身字節(jié)大小,然后去尋找對齊數(shù),對齊數(shù)的尋找方法就是將自身字節(jié)大小和默認(rèn)對齊數(shù)比較,取較小值,這樣先找到對齊數(shù),然后根據(jù)自身的字節(jié)大小去填充,就完成了成員在內(nèi)存中的存儲,最后在所有的成員已經(jīng)結(jié)束存儲,再計算最大對齊數(shù)(所有成員的對齊數(shù)中最大值),這樣就完成了計算!

我們既然已經(jīng)知道規(guī)則和計算方法,就讓我們小試牛刀一下~

四、練習(xí)

練習(xí)一:

struct s3
{
	double d;
	char c;
	int i;
};
int main()
{
	printf("%d\n", sizeof(struct s3));
	return 0;
}

上面圖片的寫法就是左邊是本身成員變量的字節(jié)大小,右邊是默認(rèn)對齊數(shù)進(jìn)行比較,最后再從對齊數(shù)中找出最大值,就是最大對齊數(shù),所以最后0~15就是存儲結(jié)構(gòu)體的大小,也就是一共16個字節(jié)

 練習(xí)二:

struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
	printf("%d\n", sizeof(struct S4));
	return 0;
}

上面是嵌套結(jié)構(gòu)體場景,結(jié)構(gòu)體S3本身大小是16,需要對齊到自身最大對齊數(shù)的位置,也就是8,然后double類型的對齊數(shù)是8,最后總字節(jié)大小也滿足最大對齊數(shù),所以一共32個字節(jié)。

五、為什么存在內(nèi)存對齊?

1、平臺原因

不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù);某些平臺只能在某些地址處取某些地址處取特定類型的數(shù)據(jù),否則拋出硬件異常

2、性能原因

數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能在自然邊界上對齊。原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需要一次訪問。

總體來說

結(jié)構(gòu)體的內(nèi)存對齊,就是讓空間換時間。 

TIP:

我們在設(shè)計結(jié)構(gòu)體時,可以人為的節(jié)省空間——讓占用空間小的成員盡量集中在一起。

例如我們之前舉的例子,盡管兩個結(jié)構(gòu)體存的成員變量一樣,但是順序不一樣,結(jié)構(gòu)體內(nèi)存大小也是不同。

六、修改默認(rèn)對齊數(shù)

對,你沒有聽錯,默認(rèn)對齊數(shù)是可以修改滴,當(dāng)我們把默認(rèn)對齊數(shù)修改為1時,結(jié)構(gòu)體的成員變量就是連續(xù)存儲的。代碼如下,計算出來的大小就是4+1+8=13

#pragma pack(1)//修改默認(rèn)對齊數(shù)為1
struct s
{
	int a;
	char b;
	double c;
};
#pragma pack()//修改默認(rèn)對齊數(shù)為默認(rèn)
int main()
{
	printf("%d\n", sizeof(struct s));
	return 0;
}

到此這篇關(guān)于詳解C語言如何計算結(jié)構(gòu)體大小(結(jié)構(gòu)體的內(nèi)存對齊)的文章就介紹到這了,更多相關(guān)C語言計算結(jié)構(gòu)體大小內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++在vscode中的多文件編程問題解讀

    C++在vscode中的多文件編程問題解讀

    這篇文章主要介紹了C++在vscode中的多文件編程問題解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • C語言實現(xiàn)流星雨效果流程

    C語言實現(xiàn)流星雨效果流程

    C本篇文章帶你用C語言去實現(xiàn)漫天流星雨的效果,代碼寫的很清晰,效果非常棒,另有視頻詳解整個過程,相信你一定能看懂,感興趣的童鞋快來看看吧
    2021-11-11
  • C++?結(jié)合?opencv讀取圖片與視頻的方法

    C++?結(jié)合?opencv讀取圖片與視頻的方法

    這篇文章主要介紹了C++?結(jié)合?opencv讀取圖片與視頻,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06
  • C/C++函數(shù)調(diào)用棧的實現(xiàn)方法

    C/C++函數(shù)調(diào)用棧的實現(xiàn)方法

    這篇文章主要介紹了C/C++函數(shù)調(diào)用棧的實現(xiàn)方法,可實現(xiàn)一個簡單的腳本解釋器,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-10-10
  • C語言中static與sizeof查缺補漏篇

    C語言中static與sizeof查缺補漏篇

    static在修飾變量的時候,如果是修飾全局變量,則跟全局變量功能一樣;如果是修改局部變量,則每次調(diào)用的時候,保持著上一次的值;而sizeof是用來判斷一個變量及數(shù)據(jù)類型所占字節(jié)數(shù)的,下面我們詳細(xì)來看看
    2022-07-07
  • C++?Protobuf實現(xiàn)接口參數(shù)自動校驗詳解

    C++?Protobuf實現(xiàn)接口參數(shù)自動校驗詳解

    用C++做業(yè)務(wù)發(fā)開的同學(xué)是否還在不厭其煩的編寫大量if-else模塊來做接口參數(shù)校驗?zāi)??今天,我們就模擬Java里面通過注解實現(xiàn)參數(shù)校驗的方式來針對C++?protobuf接口實現(xiàn)一個更加方便、快捷的參數(shù)校驗自動工具,希望對大家有所幫助
    2023-04-04
  • c++中ref的作用示例解析

    c++中ref的作用示例解析

    這篇文章主要為大家介紹了c++中ref的作用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • String底層函數(shù)的實現(xiàn)方式詳解

    String底層函數(shù)的實現(xiàn)方式詳解

    這篇文章主要介紹了String底層函數(shù)的實現(xiàn)方式,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • C++11中std::thread線程實現(xiàn)暫停(掛起)功能

    C++11中std::thread線程實現(xiàn)暫停(掛起)功能

    本文主要介紹了C++11中std::thread線程實現(xiàn)暫停(掛起)功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C++實現(xiàn)讀寫ini配置文件的示例代碼

    C++實現(xiàn)讀寫ini配置文件的示例代碼

    配置文件的讀取是每個程序必備的功能,配置文件的格式多種多樣,例如:ini格式、json格式、xml格式等。其中屬ini格式最為簡單,且應(yīng)用廣泛。本文和大家分享了C++讀寫ini配置文件的方法,需要的可以參考一下
    2023-05-05

最新評論

宜阳县| 吐鲁番市| 云南省| 贵阳市| 岚皋县| 昌邑市| 西和县| 崇信县| 平度市| 南充市| 滦南县| 遂昌县| 合水县| 南澳县| 南通市| 浦城县| 宁河县| 珲春市| 平原县| 交口县| 咸阳市| 铜梁县| 独山县| 南昌县| 梨树县| 白银市| 蓬安县| 安西县| 桐城市| 依安县| 定西市| 永城市| 康马县| 惠安县| 自贡市| 张家界市| 铁力市| 河源市| 上林县| 赤峰市| 威信县|