sizeof()C结构的一部分 - 排序

时间:2011-02-02 20:12:55

标签: c struct

我想获取一些C结构中的部分数据,以部分序列化/反序列化它们,将字节从内存写入磁盘,反之亦然。

结构体事先不知道,它们是用我自己的C代码生成器(以及将序列化它的代码)动态构建的。可序列化字段将放置在结构的开头。

假设有一个包含4个字段的结构,前两个将被序列化:

typedef struct {
   int8_t x1;   
   int32_t x2;   /* 1 + 4  = 5 bytes (if packed) */
   int8_t y1;
   int32_t  y2;   /* 1 + 4  +1 + 4 = 10 bytes (if packed) */ 
}  st;

我计划抓取指向struct变量的指针,并写入/读取覆盖这两个第一个字段(n)的x1, x2字节。我不认为我需要担心对齐/打包,因为我不打算序列化在不同的编译中存活(只有一个唯一的可执行文件可以读/写数据)。而且,由于我的目标是广泛的编译器 - 体系结构,我不想对对齐包装或编译器特定的技巧进行假设。

然后,我需要计算字节数。我不能只因为alingment-padding而sizeof(st.x1)+sizeof(st.x2)。所以,我打算从结构的开头到第一个“非持久”字段减去指针:

st myst;
int partsize = (char*)&myst.y1 - (char*)(&myst);
printf("partial size=%d (total size=%d)\n",partsize,sizeof(myst));  

这似乎有效。它可以放在宏中。

(对于记录:我还尝试编写另一个不需要结构实例的宏,比如this,但这里似乎没有 - 但这对我来说并不重要。)< / p>

我的问题:这是正确和安全的吗?你能看到任何潜在的陷阱,或者更好的方法吗?

除此之外:C标准(和事实上的编译器)是否假设结构域在内存中的顺序与在源中定义的顺序相同?这可能是一个愚蠢的问题,但我想确定......

更新:答案中的一些结论和我自己的发现:

  1. 我的方法似乎没有问题。特别是,C规定结构字段永远不会改变顺序。

  2. 也可以(根据aswer的建议)计算最后一个持久字段并计算其大小:(char*)&myst.x2 + sizeof(&myst.x2) - (char*)(&myst)。这将是等效的,除了它不包括最后一个字段的填充字节(如果存在)。

  3. 。这是一个非常小的优点 - 而且是一个非常小的缺点
  4. 但接受的答案offsetof似乎比我的建议更可取。它是清晰的表达和纯编译时间,它不需要结构的实例。它似乎是标准的,可在任何编译器中使用。 如果一个人不需要编译时构造,并且有一个可用的结构实例(就像我的场景一样),那么这两个解决方案基本上是等价的。

5 个答案:

答案 0 :(得分:10)

你看过offsetof设施了吗?它从结构的开头返回成员的偏移量。所以offsetof (st, x2)从结构的开头返回x2的偏移量。因此,在您的示例中,offsetof (st, x2) + sizeof(st.x2)将为您提供序列化组件的字节数。

这与你现在正在做的非常类似,你只需要忽略x2之后的填充并使用一个很少使用的C片段。

答案 1 :(得分:5)

C保证了这种行为。它旨在允许原始多态性。考虑:

struct X {
   int a;
};
struct Y {
   int a;
   int b;
};
void foo(X* x) {
   x->a = 10;
};
Y y;
foo((X*)&y); // Well defined behaviour- y.a = 10.

答案 2 :(得分:3)

C编译器可以插入填充字节以进行对齐,但可能不会对结构变量重新排序。

更简洁的方法可能是为sizeof()目的定义第二个结构,其中包括所需结构的起始变量。编译器将保证具有相同顺序的相同变量的2个struts将以相同的方式布局。

答案 3 :(得分:0)

您可以查看protobuf;它似乎以便携的方式做你想做的事。

答案 4 :(得分:0)

我投票支持KISS原则。按元素写入文件元素,保证没有编译器依赖。