在不使用pragma的情况下禁用C中的结构填充

如何在不使用pragma的情况下禁用C中的结构填充?

没有标准的方法可以做到这一点。 该标准规定填充可以由实现自行决定。 来自C99 6.7.2.1 Structure and union specifiers ,第12段:

结构或联合对象的每个非位字段成员以适合其类型的实现定义方式对齐。

话虽如此,你可以尝试一些事情。


第一个你已经打折,使用#pragma试图说服编译器不要打包。 无论如何,这不是便携式的。 也没有任何其他特定于实现的方法,但您应该检查它们,因为如果您确实需要此function,可能需要这样做。


第二种是按从大到小的顺序对字段进行排序,例如所有long long类型后跟long ,然后是所有intshort和finally char类型。 这通常会起作用,因为它通常是具有更严格的对齐要求的较大类型。 再次,不便携。


第三,您可以将类型定义为char数组并转换地址以确保没有填充。 但请记住,如果变量未正确对齐,某些架构将会变慢,而其他架构将失败(例如,引发BUS错误并终止您的过程)。

最后一个进一步解释。 假设您的结构具有以下顺序的字段:

 char C; // one byte int I; // two bytes long L; // four bytes 

使用填充,您可能会得到以下字节:

 CxxxIIxxLLLL 

其中x是填充。

但是,如果将结构定义为:

 typedef struct { char c[7]; } myType; myType n; 

你得到:

 CCCCCCC 

然后你可以这样做:

 int *pInt = &(nc[1]); int *pLng = &(nc[3]); int myInt = *pInt; int myLong = *pLng; 

为你带来:

 CIILLLL 

不幸的是,不再是便携式的。


所有这些“解决方案”都依赖于您对编译器和底层数据类型的深入了解。

除了pragma pack之类的编译器选项,你不能,填充是在C标准中。

您总是可以通过在结构中声明最后的最小类型来尝试减少填充:

 struct _foo { int a; /* No padding between a & b */ short b; } foo; struct _bar { short b; /* 2 bytes of padding between a & b */ int a; } bar; 

注意具有4字节边界的实现

在某些体系结构中,如果要求处理未对齐的数据,CPU本身将会反对。 为了解决这个问题,编译器可以生成多个对齐的读或写指令,移位和拆分或合并各个位。 您可以合理地预期它比对齐数据处理慢5到10倍。 但是,标准并不要求编制者做好准备……考虑到性能成本,它只是没有足够的需求。 支持显式控制填充的编译器提供了自己的编译指令,因为编译指示是为非标准function保留的。

如果您必须使用未填充的数据,请考虑编写自己的访问例程。 您可能想要尝试需要较少对齐的类型(例如,使用char / int8_t),但仍有可能例如结构的大小将四舍五入为4的倍数,这会严重阻碍打包结构,在这种情况下,您可以我需要为整个内存区域实现自己的访问权限。

要么让编译器执行填充,要么告诉它不要使用#pragma,要么只是使用像char数组那样的一些字节,而是自己构建所有数据(移位和添加字节)。 这实际上是低效的,但您将完全控制字节的布局。 我这样做有时会手工准备网络数据包,但在大多数情况下,这是一个坏主意,即使它是标准的。

如果你真的想要没有填充的结构:使用仅由8位字节组成的结构或类,为short,int,long等定义替换数据类型。 然后使用替换数据类型组成更高级别的结构。

C ++的运算符重载非常方便,但是你可以使用结构而不是类在C中实现相同的效果。 下面的强制转换和赋值实现假设CPU可以处理未对齐的32位整数,但其他实现可以适应更严格的CPU。

这是示例代码:

 #include  #include  class packable_int { public: int8_t b[4]; operator int32_t () const { return *(int32_t*) b; } void operator = ( int32_t n ) { *(int32_t*) b = n; } }; struct SA { int8_t c; int32_t n; } sa; struct SB { int8_t c; packable_int n; } sb; int main () { printf ( "sizeof sa %d\n", sizeof sa ); // sizeof sa 8 printf ( "sizeof sb %d\n", sizeof sb ); // sizeof sb 5 return 0; } 

我们可以使用以下任何一种方法禁用c程序中的结构填充。

– >使用__attribute__((packed))后面的结构定义。 例如。

 struct node { char x; short y; int z; } __attribute__((packed)); 

– >编译c代码时使用-fpack-struct标志。 例如。

$ gcc -fpack-struct -o tmp tmp.c

希望这可以帮助。 谢谢。