【问题标题】:Byte Alignment for integer (or other) types in a uint8_t arrayuint8_t 数组中整数(或其他)类型的字节对齐
【发布时间】: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_tint32_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


【解决方案1】:

并非所有处理器都如此。

如果我在设计低级 API,在一个重要的处理器上,我会做类似的事情 void *my_alloc(size_t size, size_t align)

如果调用者正在操作字符数组,他们会传递 1 的 align。对于各种小类型,他们会传递 sizeof(short)sizeof(int) 等。

然后给他们一个无能的分配器,其中 align 是MIN(roundup_to_power_of_2(size), SIZE_ON_THIS_ARCH_THATS_ALWAYS_GOOD_ENOUGH)

不,round_up_to_power_of_2 不是标准函数(或宏);-)

【讨论】:

  • 感谢您的建议,但此解决方案不适用于我。查看我的评论,但我想我已经找到了我想要的东西。
【解决方案2】:

一个简单的解决方案是将所需的对齐方式作为第二个参数传递给您编写的函数,该函数将获得指向已分配内存的指针

【讨论】:

  • 这不是那么容易。我的内存管理器有一个碎片整理例程,可以移动内存(它使用指针间接来确保原始指针有效)。要求对齐某些数据而不是其他数据会使事情复杂化——我必须确保不要将对齐的数据移动到未对齐的数据中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-11-06
  • 2020-04-22
  • 2012-11-28
相关资源
最近更新 更多