【发布时间】:2015-06-23 16:27:34
【问题描述】:
我正在为使用uint8_t 数组作为池的微控制器编写内存管理器。从这个池中,它将请求大小的内存分配给用户。
我正在研究其他内存实现。 Contiki 有一个名为 mmem。在他们的文档中,他们声明:
需要注意的是mmem_alloc()分配的内存是1字节 对齐。这与 malloc() 所做的不同。记忆 用 malloc() 分配的每个数据类型都适当对齐,并且 返回的 void 指针可以安全地转换为任何其他指针 输入。
相反,指向由 mmem_alloc() 分配的内存的指针不能 安全地转换为除 char*、signed char* 或 无符号字符*。
这意味着如果分配的内存块用于存储 结构类型的内容,要么该结构必须声明为打包 或必须使用 memcpy()。使用 GCC 可以指定打包结构 使用以下语法:
...
所以这是一个我从未意识到的非常大的问题。
几个问题:
-
这适用于所有架构吗?我正在阅读Wikipedia,他们指出大多数架构都支持未对齐的数据,这只会减慢速度。
(对于 x68):但是,也有未对齐访问的指令,例如 MOVDQU。
Contiki 链接谈到了打包结构体以解决对齐问题。有没有办法“打包”
uint16_t或int32_t值?我为用户提供了用于常见数据访问的宏,所以这可能是一个可能的解决方案
ARM 处理器是否支持自动非对齐访问? x86怎么样?真的有这么多陷阱吗?
我应该只允许对齐的分配请求,并填写任何其他数据吗?这对我来说会很烦人。
编辑:
感谢您提供有用的答案,但是由于内存管理器的工作方式,我无法在用户请求对齐的地方写一些东西(它必须通过移动数据进行碎片整理——我不愿意增加担心对齐方式的复杂性有些数据是,因为这会显着影响整个系统的性能)
似乎在我的系统 (Ubuntu) 和我所针对的 ARM 内核上,数据对齐都不是问题。
来自here:
-munaligned-access-mno-unaligned-access启用(或禁用)从非 16 位或 32 位对齐的地址读取和写入 16 位和 32 位值。 默认情况下,所有 pre-ARMv6 和所有 ARMv6-M 架构,并支持所有其他架构。...
此外,以下代码可以在我的 (x86_64 Ubuntu 14.04) 系统上执行您希望它执行的操作:
#include "stdio.h"
int main(){
char data[100];
unsigned int *value;
// Some random data
unsigned int check = (unsigned int)0x324FE23A;
// make the pointer unaligned
value = (unsigned int *)(data + 1);
*value = check;
printf("bool=%u, value=%x, check=%x\n", *value==check, *value, check);
return 0;
}
当我编译并运行它时:
$ cc playground cc align.c && ./a.out
bool=1, value=324fe23a, check=324fe23a
解决方案:
我将添加一个预编译器标志以请求以文字形式完成请求,以便所有数据自动对齐。但是,对于我目前所针对的系统,这应该是不必要的。
悬而未决的问题:
如果有人知道怎么做:
#define tm_uint16_p(index) ((uint16_t *)tm_void_p(index))
在某种程度上,tm_void_p(index) 是否对齐都无关紧要那太好了。
注意:上面只是将索引转换为 void 指针,然后将其转换为 uint16_t 指针。显然,在某些系统上,这会由于对齐问题而失败——它们是一种指定编译器只处理它的方法吗?
【问题讨论】:
-
您的大部分问题都将在这里得到解答:What is the purpose of memory alignment?。还要注意aliasing 的问题。
-
即使对齐不是必需的(即代码在没有对齐的情况下不会崩溃),它通常比正确对齐的代码执行得慢。
-
感谢 FUZxxl 的评论!这绝对是一个好点。速度不是此应用程序的第一要务,但如果用户有此问题,我将允许用户指定“仅对齐数据”。
标签: c memory-management memory-alignment