這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

上一節我們討論了C語言程序中“內存對齊”的概念以及原因,其實歸根結底都是為了效率最大化,畢竟高效率是C語言程序的一個重要特性。

這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

內存對齊很簡單

來看看這個面試題

瀏覽外文網站時,我發現了一個關於“內存對齊”的面試題目,原題主對這一個面試題完全沒有概念,即使谷歌之也沒有辦法。題目是這樣的:

memset_16aligned() 函數需要一個 16 字節對齊的指針作為參數,否則就會崩潰。a) 你能分配 1024 字節內存,並且將其 16 字節對齊嗎?b) 分配後,將其傳遞給 memset_16aligned() 函數執行後,釋放這段內存。
{ 
void *mem;
void *ptr;
// answer a) here
memset_16aligned(ptr, 0, 1024);
// answer b) here
}
這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

來看看這個面試題

解析

題目要求傳遞給 memset_16aligned() 函數的 ptr 參數是 16 字節對齊的,這很好實現,只要保證 ptr 的地址值是 16 的整數倍就可以了。進一步分析問題,還能夠發現,ptr 應該指向一段 1024 字節的內存,因此相關的C語言代碼可以這樣寫:

{
void *mem = malloc(1024+16);
void *ptr = ((char *)mem+16) & ~(char *)0x0F;
memset_16aligned(ptr, 0, 1024);
free(mem);
}

第一步就是分配一塊足夠大的內存,由於內存必須是 16 字節對齊的,以防萬一,我們多分配了 16 字節,便於調整 ptr 指針的值。16 個連續數字裡,必定至少有一個數能夠被 16 整除,因此在前 16 個字節的某處,必定有一個 16 字節對齊的地址。

這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

前 16 個字節的某處,必定有一個 16 字節對齊的地址

下一步是將 void 指針轉換為 char 指針,這是為了儘量避免對 void 指針指向指針算術。然後對轉換後的指針加上 16。

假設 malloc() 函數分配的內存起始地址為 0x800001,顯然未 16 字節對齊。現在對起始地址加 16,得到 0x800011,現在我想四捨五入到 16 字節邊界,所以可以將最後的 4 位置 0,也即 & ~0x0F。此時我們得到了 0x800010,這個地址顯然滿足 16 字節對齊。

讀者可以自己嘗試對其他地址執行上述操作,觀察是否能夠得到 16 字節對齊的地址。

最後一步,釋放分配的內存很簡單,只需調用 free() 函數就可以了。但是應該注意,傳遞給 free() 函數的必須是 malloc() 函數返回的地址,也即 mem,而不能是 ptr,否則C語言程序就會崩潰。

這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

否則C語言程序就會崩潰

題外話

可能有讀者知道自己使用的系統中 malloc() 函數的內部實現,可能它返回的地址必定是 16 字節對齊的(或者 8 字節對齊,4 字節對齊等等),那麼似乎就不再需要 ptr,直接使用 mem 就可以了。

然而,這是不可靠的也是不可移植的實現,因為其他平臺中的 malloc() 實現可能具有不同的最小對齊。作為C語言程序員,除非有某些限制,否則總是應該嘗試寫出可移植的C語言代碼。

其他問題

這個面試題目也引發了一些爭論,我覺得比較有意思的是這樣的一個觀點:“題目要求分配的是 [1024] 個字節!”也即這個觀點強調 1024 字節,而我們上面的C語言代碼分配的不止 1024 個字節。

這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

我揣測此時面試官應該有兩種意思

其實,上面的C語言代碼是將題目理解成“分配一款足以容納 1024 字節數據的內存”了,如果面試官真的強調了 1024 字節,那麼問題就更加有趣了,我揣測此時面試官應該有兩種意思。

一是要求我們分配 1024 字節的內存,並對這段內存做 16 字節對齊處理。可是這樣我們最終得到的可用內存實際上是 1008 到 1024 之間的大小。

再就是要求我們自定義一個內存分配器,該內存分配器返回的內存起始地址必定是 16 字節對齊的。這樣一來,我們在內存分配器內部可能的實現就是基於上面的C語言代碼示例了,只不過,我們會把多出的字節隱藏在模塊內部了。

這個C語言面試題看起來很懵,如何分配一段16字節對齊的內存?

歡迎在評論區一起討論,質疑。文章都是手打原創,每天最淺顯的介紹C語言、linux等嵌入式開發,喜歡我的文章就關注一波吧,可以看到最新更新和之前的文章哦。


分享到:


相關文章: