日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

[转]C++结构体|类 内存对齐详解

發(fā)布時間:2025/3/21 c/c++ 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]C++结构体|类 内存对齐详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?內(nèi)存地址對齊,是一種在計算機內(nèi)存中排列數(shù)據(jù)(表現(xiàn)為變量的地址)、訪問數(shù)據(jù)(表現(xiàn)為CPU讀取數(shù)據(jù))的一種方式,包含了兩種相互獨立又相互關(guān)聯(lián)的部分:基本數(shù)據(jù)對齊和結(jié)構(gòu)體數(shù)據(jù)對齊 。

? ? ? ?為什么需要內(nèi)存對齊?對齊有什么好處?是我們程序員來手動做內(nèi)存對齊呢?還是編譯器在進行自動優(yōu)化的時候完成這項工作?

? ? ? ?在現(xiàn)代計算機體系中,每次讀寫內(nèi)存中數(shù)據(jù),都是按字(word,4個字節(jié),對于X86架構(gòu),系統(tǒng)是32位,數(shù)據(jù)總線和地址總線的寬度都是32位,所以最大的尋址空間為232 = 4GB(也 許有人會問,我的32位XP用不了4GB內(nèi)存,關(guān)于這個不在本篇博文討論范圍),按A[31,30…2,1,0]這樣排列,但是請注意為了CPU每次讀寫 4個字節(jié)尋址,A[0]和A[1]兩位是不參與尋址計算的。)為一個塊(chunks)來操作(而對于X64則是8個字節(jié)為一個快)。注意,這里說的 CPU每次讀取的規(guī)則,并不是變量在內(nèi)存中地址對齊規(guī)則。既然是這樣的,如果變量在內(nèi)存中存儲的時候也按照這樣的對齊規(guī)則,就可以加快CPU讀寫內(nèi)存的速 度,當(dāng)然也就提高了整個程序的性能,并且性能提升是客觀,雖然當(dāng)今的CPU的處理數(shù)據(jù)速度(是指邏輯運算等,不包括取址)遠比內(nèi)存訪問的速度快,程序的執(zhí) 行速度的瓶頸往往不是CPU的處理速度不夠,而是內(nèi)存訪問的延遲,雖然當(dāng)今CPU中加入了高速緩存用來掩蓋內(nèi)存訪問的延遲,但是如果高密集的內(nèi)存訪問,一 種延遲是無可避免的,內(nèi)存地址對齊會給程序帶來了很大的性能提升。

? ? ? ?內(nèi)存地址對齊是計算機語言自動進行的,也即是編譯器所做的工作。但這不意味著我們程序員不需要做任何事情,因為如果我們能夠遵循某些規(guī)則,可以讓編譯器做得更好,畢竟編譯器不是萬能的。

? ? ? ?為了更好理解上面的意思,這里給出一個示例。在32位系統(tǒng)中,假如一個int變量在內(nèi)存中的地址是0x00ff42c3,因為int是占用4個字節(jié),所以它的尾地址應(yīng)該是0x00ff42c6,這個時候CPU為了讀取這個int變量的值,就需要先后讀取兩個word大小的塊,分別是0x00ff42c0~0x00ff42c3和0x00ff42c4~0x00ff42c7,然后通過移位等一系列的操作來得到,在這個計算的過程中還有可能引起一些總線數(shù)據(jù)錯誤的。但是如果編譯器對變量地址進行了對齊,比如放在0x00ff42c0,CPU就只需要一次就可以讀取到,這樣的話就加快讀取效率。

? ? ? ?1、基本數(shù)據(jù)對齊
? ? ? ? ? ? ? ? ?在X86,32位系統(tǒng)下基于Microsoft、Borland和GNU的編譯器,有如下數(shù)據(jù)對齊規(guī)則:
? ? ? ? ? ? ? ? ?a、一個char(占用1-byte)變量以1-byte對齊。
? ? ? ? ? ? ? ? ?b、一個short(占用2-byte)變量以2-byte對齊。
? ? ? ? ? ? ? ? ?c、一個int(占用4-byte)變量以4-byte對齊。
? ? ? ? ? ? ? ? ?d、一個long(占用4-byte)變量以4-byte對齊。
? ? ? ? ? ? ? ? ?e、一個float(占用4-byte)變量以4-byte對齊。
? ? ? ? ? ? ? ? ?f、一個double(占用8-byte)變量以8-byte對齊。
? ? ? ? ? ? ? ? ?g、一個long double(占用12-byte)變量以4-byte對齊。
? ? ? ? ? ? ? ? ?h、任何pointer(占用4-byte)變量以4-byte對齊。

? ? ? ? ? ? ? ? 而在64位系統(tǒng)下,與上面規(guī)則對比有如下不同:
? ? ? ? ? ? ? ? ?a、一個long(占用8-byte)變量以8-byte對齊。
? ? ? ? ? ? ? ? ?b、一個double(占用8-byte)變量以8-byte對齊。
? ? ? ? ? ? ? ? ?c、一個long double(占用16-byte)變量以16-byte對齊。
? ? ? ? ? ? ? ? ?d、任何pointer(占用8-byte)變量以8-byte對齊。

? ? ? ?2、結(jié)構(gòu)體數(shù)據(jù)對齊
? ? ? ?結(jié)構(gòu)體數(shù)據(jù)對齊,是指結(jié)構(gòu)體內(nèi)的各個數(shù)據(jù)對齊。在結(jié)構(gòu)體中的第一個成員的首地址等于整個結(jié)構(gòu)體的變量的首地址,而后的成員的地址隨著它聲明的順序和實際占用的字節(jié)數(shù)遞增。為了總的結(jié)構(gòu)體大小對齊,會在結(jié)構(gòu)體中插入一些沒有實際意思的字符來填充(padding)結(jié)構(gòu)體。

? ? ? ?在結(jié)構(gòu)體中,成員數(shù)據(jù)對齊滿足以下規(guī)則:
? ? ? ? a、結(jié)構(gòu)體中的第一個成員的首地址也即是結(jié)構(gòu)體變量的首地址。
? ? ? ? b、結(jié)構(gòu)體中的每一個成員的首地址相對于結(jié)構(gòu)體的首地址的偏移量(offset)是該成員數(shù)據(jù)類型大小的整數(shù)倍。
? ? ? ? c、結(jié)構(gòu)體的總大小是對齊模數(shù)(對齊模數(shù)等于#pragma pack(n)所指定的n與結(jié)構(gòu)體中最大數(shù)據(jù)類型的成員大小的最小值)的整數(shù)倍。

?

? ?7: ?struct

? ?8: ?{
? ?9: ? ? ?char a;
? 10: ? ? ?int b;
? 11: ? ? ?short c;
? 12: ? ? ?char d;
? 13: ?}dataAlign;
? 14: ??
? 15: ?struct
? 16: ?{
? 17: ? ? ?char a;
? 18: ? ? ?char d;
? 19: ? ? ?short c;
? 20: ? ? ?int b;
? 21: ? ? ?
? 22: ?}dataAlign2;

? ? ? ?仔細觀察,會發(fā)現(xiàn)雖然是一樣的數(shù)據(jù)類型的成員,只不過聲明的順序不同,結(jié)構(gòu)體占用的大小也不同,一個8-byte一個12-byte。為什么這樣,下面進行具體分析。 ?
? ? ? ?首先來看dataAlign2,第一個成員的地址等于結(jié)構(gòu)體變量的首地址,第二個成員char類型,為了滿足規(guī)則b,它相對于結(jié)構(gòu)體的首地址的偏移量必須 是char=1的倍數(shù),由于前面也是char,故不需要在第一個和第一個成員之間填充,直接滿足條件。第三個成員short=2如果要滿足規(guī)則b,也不需 要填充,因為它的偏移量已經(jīng)是2。同樣第四個也因為偏移量int=4,不需要填充,這樣結(jié)構(gòu)體總共大小為8-byte。最后來驗證規(guī)則c,在VC中默認 的#pragma pack(n)中的n=8,而結(jié)構(gòu)體中數(shù)據(jù)類型大小最大的為第四個成員int=4,故對齊模數(shù)為4,并且8 mode 4 = 0,所以滿足規(guī)則c。這樣整個結(jié)構(gòu)體的總大小為8。

? ? ? ?對于dataAlign,第一個成員等于結(jié)構(gòu)體變量首地址,偏移量為0,第二個成員為int=4,為了滿足規(guī)則b,需要在第一個成員之后填充3-byte,讓它相對于結(jié)構(gòu)體首地址偏移量為4,結(jié)合運行結(jié)果,可知&dataAlign.a = 0x01109140,而&dataAlign.b = 0x01109144,它們之間相隔4-byte,0x01109141~0x01109143三個字節(jié)被0填 充。第三個成員short=2,無需填充滿足規(guī)則b。第四個成員char=1,也不需要填充。結(jié)構(gòu)體總大小相加4 + 4 + 2 + 1 = 11。同樣最后需要驗證規(guī)則c,結(jié)構(gòu)體中數(shù)據(jù)類型大小最大為第二個成員int=4,比VC默認對齊模數(shù)8小,故這個結(jié)構(gòu)體的對齊模數(shù)仍然為4,顯然11 mode 4 != 0,故為了滿足規(guī)則c,需要在char后面填充一個字節(jié),這樣結(jié)構(gòu)體變量dataAlign的總大小為4 + 4 + 2 + 2 = 12。

總結(jié)

以上是生活随笔為你收集整理的[转]C++结构体|类 内存对齐详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。