用于多处理器数据通信的结构包装

时间:2014-04-04 16:54:44

标签: c embedded

在我们的ASIC上,我们有两个处理器,这意味着两个不同的编译器行为略有不同。我们在两者之间传递了充满数据的结构用于通信,这种情况经常发生在每秒,因此我们没有太多时间在这里进行刻录。

问题在于两个编译器都以不同方式处理填充。因此,当我们将数据从一个域复制到另一个域时,我们得到的值不正确。我们最初的解决方案是在结构内的所有内容上加上属性((压缩)。虽然这似乎在大多数时间都有效,但它绝不是便携式的。当我们将代码移动到不同的平台时,我注意到并非所有编译器都理解属性((压缩))并且我想保持代码可移植性。

有没有人在这处理过这类问题?你会推荐什么?

提前致谢!

3 个答案:

答案 0 :(得分:3)

我会手动打包这样的结构,因此任何编译器,现在或将来都没有填充问题。

乏味,但它是一种便携的面向未来的解决方案,值得付出努力。

答案 1 :(得分:2)

C 中的基本结构排列不是可移植的,因此__attribute__((packed))或类似的通常是在结构上强加固定布局的典型方法。

另一种选择是在适当的位置手动添加pad字段,并了解每个平台的对齐约束,以确保两个平台上的两个结构匹配 - 但这基本上是手动的attribute((packed))

请注意,矮人的pahole实用程序announcementpaper)是检查和查看结构对齐的绝佳工具,假设您的编译器发出ELF文件。

答案 2 :(得分:0)

这就是为什么不应该将结构用于数据协议的原因。这可能看起来像一个苛刻的事情,但不幸的是结构不便携,因此很危险。你可以考虑做这样的事情(伪代码):

typedef struct
{
  uint32_t x;
  uint16_t y;
  ...
} my_struct_t;  // some custom struct

#define PROTOCOL_SIZE ( sizeof(uint32_t) + sizeof(uint16_t) + ... )


void pack (uint8_t raw_data[PROTOCOL_SIZE], 
           const my_struct_t* ms)
{
  uint16_t i=0;

  memcpy(&raw_data[i], ms->x, sizeof(ms->x));
  i += sizeof(ms->x);

  memcpy(&raw_data[i], ms->y, sizeof(ms->y));
  i += sizeof(ms->y);

  ...
}

然后创建一个类似的unpack()函数,将原始数据复制到struct中。

这样做的好处是:100%便携。如果协议指定了特定的字节顺序,则此函数也可以处理该转换(无论如何,您都必须这样做。)

缺点是一个额外的内存缓冲区和一些额外的数据复制。