我有嵌入式设备连接到PC
以及一些具有许多字段和自定义类型FixedPoint_t数组的大结构S.
FixedPoint_t是一个模板化的POD类,只有一个数据成员,大小从char到long不等,具体取决于模板参数。无论如何,它通过了static_assert((std::is_pod<FixedPoint_t<0,8,8> >::value == true),"");
如果这个大结构在嵌入式系统和控制PC上具有兼容的内存表示,那将是一件好事。这允许将通信协议显着简化为诸如“设置具有偏移N到值V的字/字节”的命令。假设两个平台上的endianess都是相同的。
我在这里看到3个解决方案:
使用双面打包的#pragma。 但是当我将属性((压缩))添加到struct S声明时,我收到了警告 警告:由于解压缩的非POD字段而忽略压缩属性。 这是因为FixedPoint_t未声明为压缩。 我不希望将它声明为打包,因为这种类型在整个程序中被广泛使用并且打包会导致性能下降。
进行正确的结构序列化。这是不可接受的,因为代码膨胀,额外的RAM使用...协议将更复杂,因为我需要随机访问结构。现在我觉得这不是一个选择。
手动控制填充。我可以添加一些字段,重新排序其他字段...只是在两个平台上都没有填充。这将使我满意。但是我需要一个很好的方法来编写一个测试,告诉我填充是否存在。 我可以将sizeof()的每个字段的总和与sizeof(struct)进行比较。 我可以在两个平台上比较offsetof()每个struct字段。 两种变体都很丑陋......
你推荐什么?特别是我对测试中的手动填充控制和自动填充检测感兴趣。
编辑:在两个平台上比较sizeof(big struct)来检测布局兼容性(假设endianess相等)是否足够?我认为如果填充不同,大小应该不匹配。
EDIT2:
//this struct should have padding on 32bit machine
//and has no padding on 8bit
typedef struct
{
uint8_t f8;
uint32_t f32;
uint8_t arr[5];
} serialize_me_t;
//count of members in struct
#define SERTABLE_LEN 3
//one table entry for each serialize_me_t data member
static const struct {
size_t width;
size_t offset;
// size_t cnt; //why we need cnt?
} ser_des_table[SERTABLE_LEN] =
{
{ sizeof(serialize_me_t::f8), offsetof(serialize_me_t, f8)},
{ sizeof(serialize_me_t::f32), offsetof(serialize_me_t, f32)},
{ sizeof(serialize_me_t::arr), offsetof(serialize_me_t, arr)},
};
void serialize(void* serialize_me_ptr, char* buf)
{
const char* struct_ptr = (const char*)serialize_me_ptr;
for(int i=0; i<SERTABLE_LEN; I++)
{
struct_ptr += ser_des_table[i].offset;
memcpy(buf, struct_ptr, ser_des_table[i].width );
buf += ser_des_table[i].width;
}
}
答案 0 :(得分:1)
我强烈建议使用选项2:
要创建数据结构和ser / des表,可以使用offsetof
来获取结构中每种类型的偏移量。如果该表是包含文件,则可以在双方使用它。你甚至可以创建结构和表格,例如通过Python脚本。将其添加到构建过程可确保它始终是最新的,并且您可以避免其他类型化。
例如(在C中,只是为了得到想法):
// protocol.inc
typedef struct {
uint32_t i;
uint 16_t s[5];
uint32_t j;
} ProtocolType;
static const struct {
size_t width;
size_t offset;
size_t cnt;
} ser_des_table[] = {
{ sizeof(ProtocolType.i), offsetof(ProtocolType.i), 1 },
{ sizeof(ProtocolType.s[0]), offsetof(ProtocolType.s), 5 },
...
};
如果没有自动创建,我会使用宏来生成数据。可能包括两次文件:一个用于生成结构定义,另一个用于表。这可以通过重新定义中间的宏来实现。
你应该关心有符号整数和浮点数的表示(实现定义,浮点数可能是标准提出的IEEE754)。
作为width
字段的替代,您可以使用&#34;类型&#34;代码(例如char
映射到实现定义的类型。这样你可以添加相同宽度但不同编码的自定义类型(例如uint32_t和IEEE754 - float
)。这将完全抽象出来来自物理机器的网络协议编码(最佳解决方案)。注意注意阻碍您使用不会使代码复杂化的常见编码(字面意思)。