这个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等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。


分享到:


相關文章: