C语言内存字节对齐小结
在C語言面試和考試中經(jīng)常會遇到內(nèi)存字節(jié)對齊的問題。今天就來對字節(jié)對齊的知識進行小結(jié)一下。
首先說說為什么要對齊。為了提高效率,計算機從內(nèi)存中取數(shù)據(jù)是按照一個固定長度的。以32位機為例,它每次取32個位,也就是4個字節(jié)(每字節(jié)8個位,計算機基礎(chǔ)知識,別說不知道)。字節(jié)對齊有什么好處?以int型數(shù)據(jù)為例,如果它在內(nèi)存中存放的位置按4字節(jié)對齊,也就是說1個int的數(shù)據(jù)全部落在計算機一次取數(shù)的區(qū)間內(nèi),那么只需要取一次就可以了。如圖a-1。如果不對齊,很不巧,這個int數(shù)據(jù)剛好跨越了取數(shù)的邊界,這樣就需要取兩次才能把這個int的數(shù)據(jù)全部取到,這樣效率也就降低了。
?
內(nèi)存對齊是會浪費一些空間的。但是這種空間上得浪費卻可以減少取數(shù)的時間。這是典型的一種以空間換時間的做法。空間與時間孰優(yōu)孰略這個每個人都有自己的看法,但是C語言既然采取了這種以空間換時間的策略,就必然有它的道理。況且,在存儲器越來越便宜的今天,這一點點的空間上的浪費就不算什么了。
需要說明的是,字節(jié)對齊不同的編譯器可能會采用不同的優(yōu)化策略,以下以GCC為例講解結(jié)構(gòu)體的對齊.
一、原則:
1.結(jié)構(gòu)體內(nèi)成員按自身按自身長度自對齊。
自身長度,如char=1,short=2,int=4,double=8,。所謂自對齊,指的是該成員的起始位置的內(nèi)存地址必須是它自身長度的整數(shù)倍。如int只能以0,4,8這類的地址開始
2.結(jié)構(gòu)體的總大小為結(jié)構(gòu)體的有效對齊值的整數(shù)倍
結(jié)構(gòu)體的有效對齊值的確定:
1)當未明確指定時,以結(jié)構(gòu)體中最長的成員的長度為其有效值
2)當用#pragma pack(n)指定時,以n和結(jié)構(gòu)體中最長的成員的長度中較小者為其值。
3)當用__attribute__ ((__packed__))指定長度時,強制按照此值為結(jié)構(gòu)體的有效對齊值
二、例子
1。
struct AA{
?? ?char a;
?? ?int b;
?? ?char c;?
}aa
結(jié)果,sizeof(aa)=12
何解?首先假設(shè)結(jié)構(gòu)體內(nèi)存起始地址為0,那么地址的分布如下
0 ?a
1 ?
2
3
4 ?b
5 ?b
6 ?b
7 ?b
8 ?c
9
10
11
char的字對齊長度為1,所以可以在任何地址開始,但是,int自對齊長度為4,必須以4的倍數(shù)地址開始。所以,盡管1-3空著,但b也只能從4開始。再加上c后,整個結(jié)構(gòu)體的總長度為9,結(jié)構(gòu)體的有效對齊值為其中最大的成員即int的長度4,所以,結(jié)構(gòu)體的大小向上擴展到12,即9-11的地址空著。
2.
struct AA{
?? ?char a;
char c;?
?? ?int b;?? ?
}aa
sizeof(aa)=8,為什么呢
0 ?a
1 ?c
2
3
4 ?b
5 ?b
6 ?b
7 ?b
因為c為char類型,字對齊長度為1,所以可以有效的利用1-3間的空格。看見了吧,變量定義的位置的不同時有可能影響結(jié)構(gòu)體的大小的哦!
3.
#pragma pack(2)
struct AA{
?? ?char a;
?? ?int b;
?? ?char c;?
}aa
sizeof(aa)=10,
為什么呢?a到c只占9字節(jié)長度,因為結(jié)構(gòu)體的有效對齊長度在pack指定的2和int的4中取
較小的值2。故取2的倍數(shù)10。
如果當pack指定為8呢?那就仍然按4來對齊,結(jié)果仍然是12。
4.
struct AA{
?? ?char a;
?? ?int b;
?? ?char c;?
}__attribute__((__8__))aa
sizeof(aa)=16,)
為咩?其實a到c仍然只占9字節(jié)長度,但結(jié)構(gòu)體以8對齊,故取8的倍數(shù)16.
如果其指定2,則結(jié)果為10
?
如果pragma pack和__attribute__ 同時指定呢?以__attribute__ 的為準。
需要說明的是,不管pragma pack和__attribute__如何指定,結(jié)構(gòu)體內(nèi)部成員的自對齊仍然按照其自身的對齊值。
?
另外,不同的編譯器可能會對內(nèi)存的分布進行優(yōu)化,
例如有些編譯器會把立體1中的程序優(yōu)化成例題2的樣子。但這屬于編譯器的問題,
這里不做詳細討論。如果要作為編程的參考的話,最好當做編譯器不會做優(yōu)化,
盡量在保持代碼清晰的情況下,自己手動將例題1優(yōu)化成例題2的樣子。
如果是做題的話,按照以上原則做就可以了,不用考慮不同編譯器的特性。
總結(jié)
以上是生活随笔為你收集整理的C语言内存字节对齐小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线程安全与可重入函数
- 下一篇: malloc 背后的系统知识(虚拟内存地