C語言結(jié)構(gòu)體中內(nèi)存對(duì)齊的問題理解
前言
學(xué)C的同學(xué)應(yīng)該知道~
想精通C語言就不得不面對(duì)—指針與內(nèi)存
續(xù)上次指針的進(jìn)階,這一章我來聊一聊C語言內(nèi)存對(duì)齊的問題
學(xué)習(xí)結(jié)構(gòu)體的你有沒有注意過結(jié)構(gòu)體向系統(tǒng)申請(qǐng)的內(nèi)存為多少呢的??
思考
#include<stdio.h>
typedef struct s1
{
char a;
char b;
int c;
}s1;
typedef struct s2
{
char a;
int c;
char b;
}s2;
int main()
{
//內(nèi)存對(duì)齊的現(xiàn)象
printf("%d\n", sizeof(s1));
printf("%d\n", sizeof(s2));
return 0;
}很顯然這一段代碼就是計(jì)算s1與s2向系統(tǒng)申請(qǐng)的內(nèi)存大小
我:兩個(gè)char類型各為一,再加上應(yīng)該int類型的四,結(jié)果就是六
誠摯的喬治:你說的對(duì),但不完全對(duì),在結(jié)構(gòu)體中會(huì)出現(xiàn)內(nèi)存對(duì)齊的現(xiàn)象,不信?看結(jié)果

別慌,看到文章的最后,你(也許)就會(huì)恍然大悟
在結(jié)構(gòu)體中,內(nèi)存不是成員的大小之和
結(jié)構(gòu)體在內(nèi)存中開辟空間時(shí)內(nèi)存對(duì)齊的規(guī)則
1.結(jié)構(gòu)體中的第一個(gè)成員存放在這個(gè)結(jié)構(gòu)體的零偏移處,故第一個(gè)成員char類型的的偏移量為零
2.從第二個(gè)成員開始,每個(gè)成員都要對(duì)齊到成員對(duì)齊數(shù)的整數(shù)倍
(對(duì)齊數(shù)--成員自身大小與默認(rèn)對(duì)齊數(shù)的最小值的整數(shù)倍,如果自身大小是四,默認(rèn)對(duì)齊數(shù)是八,最終的對(duì)齊數(shù)就是四的倍數(shù)),一般情況下默認(rèn)對(duì)齊數(shù)就是八。
3.結(jié)構(gòu)體的總大小必須是最大對(duì)齊數(shù)的整數(shù)倍 。
(最大對(duì)齊數(shù)就是每個(gè)成員對(duì)齊數(shù)中的最大值)
4.如果結(jié)構(gòu)體中嵌套結(jié)構(gòu)體的情況下,嵌套的結(jié)構(gòu)體就對(duì)齊到自己成員對(duì)齊數(shù)的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的總大小就是最大對(duì)齊數(shù)(含嵌套的結(jié)構(gòu)體成員)的整數(shù)倍。
下面其中的一個(gè)結(jié)構(gòu)體進(jìn)行分析:
先向大家介紹一下本章的配角—offsetof

offsetof的返回值就是距離這個(gè)結(jié)構(gòu)體(自定義類型)起始位置的值
參數(shù)就是結(jié)構(gòu)體的名稱和結(jié)構(gòu)體成員的名稱。

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
char a;
int b;
char c;
}s;
int main()
{
//offsetof-是指偏移量
printf("%d\n", offsetof(s,a));
printf("%d\n", offsetof(s,b));
printf("%d\n", offsetof(s,c));
return 0;
}
char a; //因?yàn)閏har a是結(jié)構(gòu)體第一個(gè)成員,所以偏移量就是零
int b; //自身大小: 4 默認(rèn)對(duì)齊數(shù):8 對(duì)齊數(shù):4的倍數(shù)即可,所以偏移量就是四
char c; // 自身大小: 1 默認(rèn)對(duì)齊數(shù):8 對(duì)齊數(shù):1的倍數(shù)即可,所以偏移量就是八
又因?yàn)樽罱K的結(jié)構(gòu)體大小是成員最大對(duì)齊數(shù)的倍數(shù),也就是四的倍數(shù),所以最終的結(jié)構(gòu)體的大小應(yīng)該就是十二。

到這里是不是有一定的思路了,別急,再來一道試試吧
#include<stddef.h>
#include<stdio.h>
typedef struct s
{
double a;
char b;
int c;
}s;
int main()
{
//offsetof-是指偏移量
printf("%d\n", offsetof(s,a));
printf("%d\n", offsetof(s,b));
printf("%d\n", offsetof(s,c));
printf("%d", sizeof(s));
return 0;
}結(jié)果如下:

是不是跟你想的一樣呢?
同樣的,用一樣的方法進(jìn)行解釋
double a; //因?yàn)閐ouble a是結(jié)構(gòu)體第一個(gè)成員,所以偏移量就是零
char b; //自身大?。? 默認(rèn)對(duì)齊數(shù):8 對(duì)齊數(shù):1的倍數(shù)即可,所以偏移量就是八
int c; //自身大?。? 默認(rèn)對(duì)齊數(shù):8 對(duì)齊數(shù):4的倍數(shù)即可,所以偏移量就是十二
最終結(jié)構(gòu)體的大小就是四的整數(shù)倍十六

下面給應(yīng)該結(jié)構(gòu)體嵌套結(jié)構(gòu)體的例子
#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
char i;
char j;
int k;
}s1;
typedef struct s2
{
char a;
int c;
s1;
}s2;
int main()
{
printf("%d\n", offsetof(s2, a));
printf("%d\n", offsetof(s2, c));
printf("%d", sizeof(s2));
return 0;
}

我相信此時(shí)的你一定會(huì)計(jì)算結(jié)構(gòu)體想系統(tǒng)申請(qǐng)的大小,以及內(nèi)存對(duì)齊是咋回事
其實(shí),內(nèi)存對(duì)齊也就那么回事兒~
為什么存在內(nèi)存對(duì)齊
知道怎樣計(jì)算后,你是否和我一樣思考
為什么內(nèi)存的申請(qǐng)不能想main函數(shù)中的內(nèi)存申請(qǐng)一樣,要多少就申請(qǐng)相應(yīng)大小的空間,這樣既省內(nèi)存,也不用考慮這么多。
1.平臺(tái)的原因
所謂平臺(tái)原因就是與硬件有關(guān),硬件不能訪問內(nèi)存中的每一個(gè)空間,換句話說,就是按一定的規(guī)律進(jìn)行訪問,這樣內(nèi)存對(duì)齊就起到了很好的作用
2.性能的原因
數(shù)據(jù)結(jié)構(gòu)(尤其是棧),應(yīng)該盡可能的在自然邊界上對(duì)齊
因?yàn)槲覀兊腃PU訪問空間,就是一次性按四個(gè)字節(jié)的空間來訪問,內(nèi)存對(duì)齊在一定的時(shí)候避免了訪問一次的空間進(jìn)行了二次訪問
如下訪問應(yīng)該int類型內(nèi)存對(duì)齊后只需要訪問一次


總的來說內(nèi)存對(duì)齊就是拿空間換取時(shí)間
當(dāng)然,我們可以實(shí)現(xiàn)內(nèi)存對(duì)齊之上,也可以進(jìn)行省一定空間
就想博客開頭一道題,一模一樣的代碼,最終的結(jié)構(gòu)體的大小卻不一樣,這種就是優(yōu)化版的結(jié)構(gòu)體
這里給一個(gè)小的技巧,就是把空間小的成員盡量放在一起
到此這篇關(guān)于C語言結(jié)構(gòu)體中內(nèi)存對(duì)齊的問題理解的文章就介紹到這了,更多相關(guān)C語言 內(nèi)存對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解C語言如何計(jì)算結(jié)構(gòu)體大小(結(jié)構(gòu)體的內(nèi)存對(duì)齊)
- C語言程序中結(jié)構(gòu)體的內(nèi)存對(duì)齊詳解
- C語言中結(jié)構(gòu)體的內(nèi)存對(duì)齊規(guī)則講解
- C語言 詳細(xì)分析結(jié)構(gòu)體的內(nèi)存對(duì)齊
- C語言結(jié)構(gòu)體內(nèi)存對(duì)齊詳解
- C語言熱門考點(diǎn)結(jié)構(gòu)體與內(nèi)存對(duì)齊詳解
- C語言中結(jié)構(gòu)體與內(nèi)存對(duì)齊實(shí)例解析
- C語言結(jié)構(gòu)體內(nèi)存對(duì)齊問題小結(jié)
相關(guān)文章
C++ string字符串的使用和簡(jiǎn)單模擬實(shí)現(xiàn)
C語言中,字符串是以'\0'結(jié)尾的一些字符的集合,為了操作方便,C標(biāo)準(zhǔn)庫中提供了一些str系列的庫函數(shù),但是這些庫函數(shù)和字符串是分離的,本文給大家介紹了C++ string字符串的使用和簡(jiǎn)單模擬實(shí)現(xiàn),感興趣的朋友可以參考下2024-06-06
探討:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列(我作為面試官的小結(jié))
作為面試官的我,經(jīng)常拿這道用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的面試題來考面試者,通過對(duì)面試者的表現(xiàn)和反應(yīng),有一些統(tǒng)計(jì)和感受,在此做個(gè)小結(jié)2013-05-05
Windows系統(tǒng)vscode安裝與配置G++、Cmake的圖文步驟
本文主要介紹了Windows系統(tǒng)vscode安裝與配置G++、Cmake的步驟,文中通過圖文示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04

