先看一個(gè)例子!
我們發(fā)現(xiàn)兩個(gè)結(jié)構(gòu)體中存放的是相同類型的三個(gè)數(shù)據(jù),只是順序有所不同,通過(guò)
sizeof()
函數(shù)計(jì)算出所占字節(jié)數(shù)目也完全不同。
其實(shí)我們?cè)趯W(xué)習(xí)C語(yǔ)言的時(shí)候應(yīng)該已經(jīng)說(shuō)過(guò)這種現(xiàn)象是因?yàn)閮?nèi)存對(duì)齊所導(dǎo)致的矩屁,不過(guò)下面我們來(lái)進(jìn)一步了解下內(nèi)存對(duì)齊的規(guī)則辟宗。
PS:阿里校招的測(cè)評(píng)有一題就是考了這個(gè),見(jiàn)下圖:
為什么需要內(nèi)存對(duì)齊
所謂內(nèi)存對(duì)齊吝秕,其實(shí)是為了加快CPU讀取數(shù)據(jù)的速度泊脐,因?yàn)镃PU讀取數(shù)據(jù)是按塊(X64架構(gòu)的計(jì)算機(jī)是8個(gè)字節(jié)為一個(gè)塊)來(lái)讀取的,所以按照一定的對(duì)齊規(guī)則存儲(chǔ)數(shù)據(jù)烁峭,會(huì)大大提高CPU的讀取效率容客。
更多內(nèi)容關(guān)于內(nèi)存對(duì)齊對(duì)性能請(qǐng)參考文章
舉個(gè)例子
在32位系統(tǒng)中,假如一個(gè)int變量在內(nèi)存中的地址是0x00ff42c3,因?yàn)閕nt是占用4個(gè)字節(jié)约郁,所以它的尾地址應(yīng)該是0x00ff42c6缩挑,這個(gè)時(shí)候CPU為了讀取這個(gè)int變量的值,就需要先后讀取兩個(gè)塊鬓梅,分別是0x00ff42c00x00ff42c3和0x00ff42c40x00ff42c7供置,然后通過(guò)移位等一系列的操作來(lái)得到。但是如果編譯器對(duì)變量地址進(jìn)行了對(duì)齊绽快,比如放在0x00ff42c0芥丧,CPU就只需要一次就可以讀取到,這樣的話就加快讀取效率坊罢。
還有就是不同平臺(tái)下的硬件原因续担,一些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常活孩,并不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的物遇。
內(nèi)存對(duì)齊的規(guī)則
- 基本數(shù)據(jù)類型對(duì)齊
基本數(shù)據(jù)類型是按照其類型所占字節(jié)數(shù)來(lái)對(duì)齊的,需要注意的是憾儒,不同平臺(tái)下询兴,有些數(shù)據(jù)類型所占字節(jié)數(shù)是不一樣的,比如
指針類型在64位機(jī)器上占8個(gè)字節(jié)航夺,在32位機(jī)器上則占4個(gè)字節(jié)蕉朵。
- 結(jié)構(gòu)數(shù)據(jù)類型對(duì)齊
結(jié)構(gòu)體內(nèi)的各個(gè)數(shù)據(jù)對(duì)齊崔涂。在結(jié)構(gòu)體中的第一個(gè)成員的首地址等于整個(gè)結(jié)構(gòu)體的變量的首地址阳掐,而后的成員的地址隨著它聲明的順序和實(shí)際占用的字節(jié)數(shù)遞增。為了總的結(jié)構(gòu)體大小對(duì)齊冷蚂,會(huì)在結(jié)構(gòu)體中插入一些沒(méi)有實(shí)際意思的字符來(lái)填充(padding)結(jié)構(gòu)體缭保。下面給出規(guī)則:
1、對(duì)于結(jié)構(gòu)的各個(gè)成員蝙茶,第一個(gè)成員位于偏移為0的位置艺骂,以后每個(gè)數(shù)據(jù)成員的偏移量必須是
min(#pragma pack())指定的數(shù),這個(gè)數(shù)據(jù)成員的自身長(zhǎng)度)
的倍數(shù)隆夯。
2钳恕、在數(shù)據(jù)成員完成各自對(duì)齊之后别伏,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將按照min(#pragma pack指定的數(shù)值,結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長(zhǎng)度)
進(jìn)行對(duì)齊忧额。
#pragma pack()的預(yù)處理指令可以修改系統(tǒng)默認(rèn)的對(duì)齊數(shù)
總結(jié)
PS:聯(lián)合的大小是聯(lián)合中所占字節(jié)最多的成員
了解完規(guī)則之后厘肮,前面的例子加阿里的題目也就迎刃而解了。