在工做面試中,我剛剛完成了一次測試,一個問題困擾着我,甚至使用Google做爲參考。 我想看看StackOverflow小組能夠作什麼: 面試
memset_16aligned
函數須要一個16字節對齊的指針傳遞給它,不然它將崩潰。 函數a)您將如何分配1024個字節的內存,並將其與16個字節的邊界對齊?
b)執行memset_16aligned
後memset_16aligned
內存。 測試
{ void *mem; void *ptr; // answer a) here memset_16aligned(ptr, 0, 1024); // answer b) here }
long add; mem = (void*)malloc(1024 +15); add = (long)mem; add = add - (add % 16);//align to 16 byte boundary ptr = (whatever*)(add);
您還能夠添加一些16個字節,而後經過在指針下面添加(16-mod)將原始ptr推向16位對齊: 優化
main(){ void *mem1 = malloc(1024+16); void *mem = ((char*)mem1)+1; // force misalign ( my computer always aligns) printf ( " ptr = %p \n ", mem ); void *ptr = ((long)mem+16) & ~ 0x0F; printf ( " aligned ptr = %p \n ", ptr ); printf (" ptr after adding diff mod %p (same as above ) ", (long)mem1 + (16 -((long)mem1%16)) ); free(mem1); }
在16字節和15字節計數的填充前沿上,您須要添加以得到N對齊的實際數字是max(0,NM) ,其中M是內存分配器的天然對齊(均爲2的冪)。 spa
因爲任何分配器的最小內存對齊方式都是1個字節,所以15 = max(0,16-1)是一個保守的答案。 可是,若是您知道內存分配器將爲您提供32位int對齊的地址(這是很常見的),則可使用12做爲填充。 設計
對於此示例而言,這並不重要,可是在具備12K RAM的嵌入式系統中,每一個int保存的計數都很是重要。 指針
若是您實際上要嘗試保存全部可能的字節,則實現它的最佳方法是將其做爲宏,以便您能夠將其做爲本機內存對齊。 一樣,這可能僅對須要保存每一個字節的嵌入式系統有用。 code
在下面的示例中,在大多數系統上,對於MEMORY_ALLOCATOR_NATIVE_ALIGNMENT
,值1很好,可是對於咱們的具備32位對齊分配的理論嵌入式系統,如下內容能夠節省一小部分寶貴的內存: 內存
#define MEMORY_ALLOCATOR_NATIVE_ALIGNMENT 4 #define ALIGN_PAD2(N,M) (((N)>(M)) ? ((N)-(M)) : 0) #define ALIGN_PAD(N) ALIGN_PAD2((N), MEMORY_ALLOCATOR_NATIVE_ALIGNMENT)
特定於MacOS X: 技巧
支持C11,所以您只需調用aligned_malloc(16,大小)便可。
MacOS X會在啓動時針對memset,memcpy和memmove選擇針對單個處理器進行了優化的代碼,而且該代碼使用了您從未據說過的技巧來使其快速運行。 memset運行速度比任何手寫的memset16快99%,這使整個問題毫無心義。
若是您想要100%可移植的解決方案,那麼在C11以前沒有。 由於沒有可移植的方法來測試指針的對齊方式。 若是沒必要100%可移植,則可使用
char* p = malloc (size + 15); p += (- (unsigned int) p) % 16;
假定將指針轉換爲unsigned int時,指針的對齊方式存儲在最低位。 轉換爲unsigned int會丟失信息並由實現定義,但這不要緊,由於咱們不會將結果轉換回指針。
固然,最糟糕的部分是原始指針必須保存在某個地方纔能用它調用free()。 因此總的來講,我真的會懷疑這種設計的智慧。
若是存在約束,則不能浪費單個字節,則此解決方案有效:注意:在某些狀況下,它能夠無限執行:D
void *mem; void *ptr; try: mem = malloc(1024); if (mem % 16 != 0) { free(mem); goto try; } ptr = mem; memset_16aligned(ptr, 0, 1024);