Ada*_*erg 17 c++ packing bit-packing data-structures
在代码审查期间,我遇到了一些定义简单结构的代码,如下所示:
class foo {
unsigned char a;
unsigned char b;
unsigned char c;
}
Run Code Online (Sandbox Code Playgroud)
在其他地方,定义了这些对象的数组:
foo listOfFoos[SOME_NUM];
Run Code Online (Sandbox Code Playgroud)
之后,将结构原始复制到缓冲区中:
memcpy(pBuff,listOfFoos,3*SOME_NUM);
Run Code Online (Sandbox Code Playgroud)
此代码依赖于以下假设:a.)foo的大小为3,并且不应用填充,并且b.)这些对象的数组被打包,它们之间没有填充.
我已经在两个平台(RedHat 64b,Solaris 9)上使用GNU进行了尝试,并且它在两者上都有效.
以上假设是否有效?如果没有,在什么条件下(例如OS /编译器的变化)可能会失败?
The*_*sey 22
这样做肯定会更安全:
sizeof(foo) * SOME_NUM
Run Code Online (Sandbox Code Playgroud)
Jer*_*fin 19
对象数组必须是连续的,因此对象之间永远不会填充,尽管可以将填充添加到对象的末尾(产生几乎相同的效果).
鉴于你正在使用char,假设可能是正确的,但C++标准肯定不能保证.不同的编译器,甚至只是传递给当前编译器的标志的更改可能导致在结构的元素之间插入填充或者在结构的最后一个元素之后插入填充,或者两者兼而有之.
如果你像这样复制你的数组,你应该使用
memcpy(pBuff,listOfFoos,sizeof(listOfFoos));
Run Code Online (Sandbox Code Playgroud)
只要您将pBuff分配到相同的大小,这将始终有效.这样你就不会对填充和对齐做任何假设.
大多数编译器将结构或类与所包含的最大类型的所需对齐对齐.在你的chars的情况下,这意味着没有对齐和填充,但是如果你添加一个short,例如你的类将是6个字节大,在最后一个char和你的short之间添加一个填充字节.
我认为之所以可以这样做是因为结构中的所有字段都是char,它们对齐一个。如果至少有一个不对齐1的字段,则结构/类的对齐方式将不为1(对齐方式取决于字段顺序和对齐方式)。
让我们看一些例子:
#include <stdio.h>
#include <stddef.h>
typedef struct {
unsigned char a;
unsigned char b;
unsigned char c;
} Foo;
typedef struct {
unsigned short i;
unsigned char a;
unsigned char b;
unsigned char c;
} Bar;
typedef struct { Foo F[5]; } F_B;
typedef struct { Bar B[5]; } B_F;
#define ALIGNMENT_OF(t) offsetof( struct { char x; t test; }, test )
int main(void) {
printf("Foo:: Size: %d; Alignment: %d\n", sizeof(Foo), ALIGNMENT_OF(Foo));
printf("Bar:: Size: %d; Alignment: %d\n", sizeof(Bar), ALIGNMENT_OF(Bar));
printf("F_B:: Size: %d; Alignment: %d\n", sizeof(F_B), ALIGNMENT_OF(F_B));
printf("B_F:: Size: %d; Alignment: %d\n", sizeof(B_F), ALIGNMENT_OF(B_F));
}
Run Code Online (Sandbox Code Playgroud)
执行后,结果为:
Foo:: Size: 3; Alignment: 1
Bar:: Size: 6; Alignment: 2
F_B:: Size: 15; Alignment: 1
B_F:: Size: 30; Alignment: 2
Run Code Online (Sandbox Code Playgroud)
您会看到Bar和F_B的对齐方式为2,因此其字段i将正确对齐。您还可以看到,条形尺寸为6而不是5。类似地,B_F(Bar的5)的大小为30而不是25。
因此,如果您使用的是硬代码而不是sizeof(...),那么您会在这里遇到问题。
希望这可以帮助。