删除C结构末端填充的最佳做法是什么?

时间:2012-08-30 06:46:23

标签: c++ c struct c++11

在C或C ++中制作非压缩非填充结构的最佳方法是什么?目标是:

typedef struct {
    char first[3]; //padded to 8 because next type has size 8
    double second;
    char third;
} SomeStruct;

but do something to make sizeof(SomeStruct) be equal 17;

结构由外部库规范定义。我有两个决定:

1)

#pragma pack (push, 1)

typedef struct {
    char first[3];
        char unused[5]; // Manual padding of second field.
    double second;
    char third;
} SomeStruct;

#pragma pack (pop)

2)使用声明的第一个变体,但在序列化数据时写入(int)(&((SomeStruct*)0)->third) + sizeof(((SomeStruct*)0)->third)而不是sizeof(SomeStruct)。我不需要序列化这种结构的数组,所以可以这样做。

但他们都是肮脏的黑客。是否有一种标准方法可以去除C中的结构填充?

3 个答案:

答案 0 :(得分:2)

C11现在有_Alignas个关键字,可能会建议double

更窄的对齐方式
typedef struct {
    char first[3]; //padded to 8 because next type has size 8
    _Alignas(uint16_t) double second;
    char third;
} SomeStruct;

如果可能的话,这会做更窄的对齐,即平台上double的标准运算符能够应对这种对齐。 (如果不是你,无论如何你都被搞砸了。)

Clang已经实现了这个功能,而其他编译器(如gcc)已经有了接近它的扩展,因此您可以轻松地自己编写一个使用此语法的包装器,并且是“面向未来”。

编辑:我发帖后才看到你的问题也是关于C ++的。我认为C ++ 1具有与alignas相同的功能。 (C11通过标准头文件中的宏具有alignas -> _Alignas。)

答案 1 :(得分:1)

尝试按正确的顺序放置

#include <stdio.h>

struct s
{
    char first[3];
    char second;
    double third;
};

int main()
{
    printf("%u\n", sizeof(struct s));
    return 0;
}

答案 2 :(得分:0)

如果外部库规范的大小为17个字节,那么SomeStruct的第零个声明是不准确的。正如James McNellis在评论中指出的那样,你的版本大小为24.但是,我们可以弄明白你的意思。

SomeStruct的第一个声明完成了你所需要的,因为在任何地方都没有填充,你输入5个未使用的字节以匹配外部库规范。您的结构有17个字节。所以这看起来像你的答案。

你的第二个提案不清楚,因为你没有说你的SomeStruct的第二个声明是什么。

如果使用SomeStruct数组,则无关紧要。正如James McNellis的评论指出的那样,该标准要求编译器允许数组的可能性,无论你是否使用某些数组。

(当然这假设double是8个字节,你的pragma以你想要的方式工作,等等。)