C语言中的消息调度系统,不使用';t中断严格的别名和对齐

C语言中的消息调度系统,不使用';t中断严格的别名和对齐,c,cross-platform,message-queue,memory-alignment,strict-aliasing,C,Cross Platform,Message Queue,Memory Alignment,Strict Aliasing,我正在用C编写一个嵌入式控制系统,它由多个相互发送消息的任务组成(我相信这是一个相当常见的习惯用法!),但我很难设计一种机制: 整洁 是通用的 这是相对有效的 最重要的是:与平台无关(特别是,不违反严格的别名或对齐问题) 从概念上讲,我希望将每种消息类型表示为一个单独的结构定义,并且我希望系统具有以下功能(简化): 其中,queue\u t包含节点的链接列表,每个节点都有一个char buf[MAX\u SIZE]字段。我所在的系统没有malloc()实现,因此需要有一个全局空闲节点池,然后

我正在用C编写一个嵌入式控制系统,它由多个相互发送消息的任务组成(我相信这是一个相当常见的习惯用法!),但我很难设计一种机制:

  • 整洁
  • 是通用的
  • 这是相对有效的
  • 最重要的是:与平台无关(特别是,不违反严格的别名或对齐问题)
从概念上讲,我希望将每种消息类型表示为一个单独的结构定义,并且我希望系统具有以下功能(简化):

其中,
queue\u t
包含节点的链接列表,每个节点都有一个
char buf[MAX\u SIZE]
字段。我所在的系统没有
malloc()
实现,因此需要有一个全局空闲节点池,然后是以下之一(以粗体显示的问题):

  • sendMsg()
    将传入消息的
    memcpy
    放入空闲节点的缓冲区。
    我的理解是,这将有对齐问题,除非
    dequeueMsg()
    的调用方对返回值做进一步的
    memcpy
  • 或者会有一个
    void*getFreeBuffer()
    函数返回下一个空闲节点的
    buf[]
    ,调用者(发送者)将该节点转换为相应的类型指针。
    我的理解是,这将在进入过程中出现对齐问题,并且在
    dequeueMsg()
    之后仍然需要
    memcpy
    ,以避免在退出时出现对齐问题。
  • 或者将
    queue\u t
    节点中的缓冲区重新定义为(例如
    uint32\u t buf[MAX\u SIZE]

    我的理解是,这违反了严格的别名,并且与平台无关。
  • 我能看到的唯一其他选择是创建所有消息类型的联合,以及
    char buf[MAX_SIZE]
    ,但我不认为这是“整洁的”

    因此,我的问题是,如何正确地做到这一点?

    我不理解为什么1会出现对齐问题-只要每个
    buf[MAX_SIZE]
    元素与消息结构中出现的自然最大的单一基元类型对齐(可能是32位或64位),那么每个消息类型的内容是什么都无关紧要;因为它将始终与该尺寸对齐

    编辑


    事实上,这比那还要简单。由于消息队列中的每个元素的长度都是
    MAX\u SIZE
    ,因此假设您以自己的
    buf
    启动每个消息(即,如果消息的长度小于MAX\u SIZE,则不打包),那么队列中的每个消息都将在至少与自身一样大的边界上启动,因此,它将始终正确对齐。

    我们处理此问题的方法是让空闲列表完全由对齐的节点组成。事实上,对于不同大小的节点,我们有多个空闲列表,因此我们有在2字节、4字节和16字节边界上对齐的列表(我们的平台不关心大于一个SIMD向量的对齐)。任何分配都会向上舍入到这些值之一,并放入一个正确对齐的节点中。因此,sendMsg总是将其数据复制到对齐的节点中。由于您自己编写自由列表,因此可以轻松地执行对齐

    我们还将使用#pragma或declspec强制char buf[MAX#u SIZE]数组至少与队列节点结构内的字边界对齐

    当然,这假设输入数据是对齐的,但是如果出于某种原因,您传递的消息预期(比方说)偏离对齐3字节,则始终可以使用模来检测,并向空闲节点返回偏移量

    有了这种底层设计,我们就有了支持上述选项1和2的接口。同样,我们假设输入数据总是本机对齐的,所以我们的出列当然会返回一个对齐的指针;但是,如果您需要输入奇怪对齐的数据,请再次偏移到空闲节点并返回偏移指针


    这使您可以处理void*s,从而避免了严格的别名问题。(一般来说,我认为在编写自己的内存分配器时,您可能需要放宽严格的别名要求,因为它们本质上会在内部模糊类型。)

    感谢您提供的详细信息和想法!事实上,这是一个可以用#pragmas等来解决的问题,但是如果可能的话,我想避免这个问题,因为它会将我的代码绑定到一个特定的编译器/平台组合。我不确定是否有其他方法可以强制结构内部对齐。你是说char buf[MAX#u SIZE]是一个安全的假设吗如果MAX_SIZE>=4,将始终与(比方说)32位边界对齐?我是说,只要MAX_SIZE是一个整数(32或64位)字;然后队列数组中的每个buf元素将自然对齐。
    void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
    void *dequeueMsg(queue_t *pQueue);