詳解C語言記憶體對齊

2021-08-10 04:23:48 字數 2465 閱讀 4748

在c語言裡有乙個機制是記憶體對齊,當然不止c語言,包括其他的程式語言都會有記憶體對齊機制,否則編譯出來的軟體無法正常執行,至於為什麼呢?眾所周知,在記憶體中,所有的資料都是按位元組為最小單位儲存的,儲存單位稱為儲存單元,所以也叫記憶體是由很多儲存單元組成的,這些儲存單元(位元組)都有固定的位址標示著(這裡說的非虛擬模式下),在我們程式設計師眼裡記憶體就是乙個乙個位元組組成的,這些位元組對應的位址都是連續併排好的,但是在cpu中不是,在cpu看來記憶體是一段一段的,每段大小取決於cpu的定址位寬!

比如在c語言裡申請了short和兩個char變數:

shor a;

char b;

char c;

在我們程式設計師眼裡在記憶體中的儲存是這樣的:

但是在乙個定址位寬為32位的cpu上是這樣的:

short占用16個bit位char占用8個bit位所以16+8+8=32 剛好組成一段!

但是如果在c語言中我們這樣定義了三個變數:

那麼如果c語言編譯器不為我們自動對齊在記憶體中就會這樣:

可以看到最後乙個short的位址被分兩個段儲存了,也就是說如果cpu要讀取變數c那麼必須先將第乙個段裡的資料全部讀取出來送到暫存器裡(這裡假定通用暫存器為32位),然後將第乙個暫存器裡的0x01到0x03的資料剔除掉,將0x04上的bit位資料挪移到暫存器的低位上,然後在去讀取第二個段上的位址資料也送到暫存器裡,然後將0x06到0x08上的資料剔除掉,這樣就將額外的資料剔除掉了,但是這樣就會讀取兩次,浪費更多的時間1,為什麼不直接從0x04開始讀取?注意cpu不可以從某段的段偏移上讀取只能從某段的起始位址開始讀取!這是虛擬記憶體中的概念(詳細參見虛擬記憶體的對映關係),不然的話就會造成讀取時出現資料越界的情況!

那麼在乙個32位的cpu下定址時就會發生越界的情況,訪問到其他程序下的記憶體則會被作業系統裡核心中斷**捕捉會被視為惡意**會立即被中斷,

當然部分cpu也並不會全部都給你按上面的方式來讀取,假如遇到了上圖那樣的位址儲存方式,cpu會直接報硬體中斷,直接罷工不讀取,然後由作業系統捕捉這個硬體中斷直接咔擦掉你的程式!在除錯情況下偵錯程式捕捉這個訊息時會中斷!

所以為了解決這一問題,編譯器使用了一種叫做空間交換法的方式來對齊記憶體,也就是說增加額外的記憶體,換取時間上的效率,同時也避免部分cpu的硬體中斷!

可以看到char為了對齊short增加了乙個位元組,而short為了對齊32位定址增加了兩個位元組,這就是空間上的時間交換法,這樣的話cpu讀取時只需要一次就可以讀取完!注意增加的位元組只是為了對齊定址,額外的位元組是不允許被賦值的,雖然說可以賦值,但是當我們賦值是編譯器不會允許我們向額外的位址傳遞資料!注意以上記憶體對齊是發生在結構體當中的,不光是結構體在函式體裡所有的變數包括**段記憶體全部都會被記憶體對齊,函式體裡的對齊方式不同於結構體,博主也沒有去深刻的去查函式體裡的對齊方式,這裡也不必要做過多的了解因為編譯器都會幫我們做好!只是在個別面試時會面試到關於記憶體對齊的基礎題!

這裡來做乙個演示:

下面是乙個結構體

struct st{

inta;

charb;

intc;

sizeof的大小是多少?通過上面的說明應該可以斷定大小為:12,為什麼不是9?上面也說過了記憶體對齊!a剛好為32位的定址寬,而b則不滿足32位定址寬,所以它需要與a進行乙個記憶體對齊的情況,所以就額外遞增了3個位元組給b滿足32位的定址寬,而c則不需要對齊因為它剛好滿足32位的定址寬!

假如還有乙個結構體:

struct st{

shorta;

charb;

intc;

sizeof的大小是多少?答:8,應該可以很容易的算出來,首先short a的占用位元組為2(16bit)不滿足32位定址,而charb(8bit)占用一位元組,這個時候呢編譯器會給b填充乙個位元組讓其與a對齊,然後將a與b看成一段!這樣a與b都是16位bit相加在一起就是32位定址,剛好滿足位寬為32位的cpu定址!

這種方法就是空間上的時間轉換,犧牲額外的空間換取時間上的效率,畢竟在這個記憶體越來越大,**越來越便宜的年代,犧牲額外的記憶體換取效率也是一件可行之事!

每個編譯器裡都有乙個記憶體對齊的模數,這個摸數取決於你的cpu位寬!我們可以通過##pragma pack(n)

來強制改變它,

n的可取值範圍是:

n=1,2,4,8,16(位元組)

,當然這裡也不是特別建議去改變它的預設定址寬度,因為超出的話

cpu沒有辦法一次性讀取完還是會分段裁剪來讀,過小的話

cpu也是要去分兩次或者更多的次數然後裁剪的讀取,所以建議為默

c語言記憶體對齊詳解

一 什麼是位元組對齊,為什麼要對齊?現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。對齊的作...

C語言 記憶體位元組對齊詳解

一 什麼是對齊,以及為什麼要對齊 1.現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定變數的時候經常在特定的記憶體位址訪問,這就需要各型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。2.對齊的作...

C語言記憶體對齊詳解(2)

vc對結構的儲存的特殊處理確實提高cpu儲存變數的速度,但是有時候也帶來了一些麻煩,我們也遮蔽掉變數預設的對齊方式,自己可以設定變數的對齊方式。vc 中提供了 pragma pack n 來設定變數以n位元組對齊方式。n位元組對齊就是說變數存放的起始位址的偏移量有兩種情況 第一 如果n大於等於該變數...