C++ 打包结构/避免填充

C++ 打包结构/避免填充,c++,c,gcc,struct,C++,C,Gcc,Struct,我有以下结构: struct SkipListNode{ void *data; // 8 bytes uint8_t size; // 1 byte // 7 bytes padding here... void *next[1]; // dynamic array, 8 bytes each "cell" }; 我使用的是malloc(),我分配的空间比sizeof(SkipListNode)多,

我有以下结构:

struct SkipListNode{
    void        *data;      // 8 bytes
    uint8_t     size;       // 1 byte
    // 7 bytes padding here...
    void        *next[1];   // dynamic array, 8 bytes each "cell"
};
我使用的是
malloc()
,我分配的空间比
sizeof(SkipListNode)
多,因此我扩展了
next[]
数组

我想避免
7个字节的浪费。我可以完全删除大小字段,但是我应该在数组末尾保留single
NULL
(8字节)。但是,这无助于减小尺寸

我应该使用
\uuuuuuuuuuuuuuuuuuu属性((\uuuuuuuuuuuuuuuuuuuu))吗
或者我可以用不同的方法来做这个把戏

这必须在C和C++下编译。

编译器是gcc。

#包括
#include <stdio.h>
#include <stdint.h>

struct SkipListNode{
    void        *data;      // 8 bytes
    uint8_t     size;       // 1 byte
    void *next[1];
    };

struct SkipListNode_pack{
    void        *data;      // 8 bytes
    uint8_t     size;       // 1 byte
    void *next[1];
    } __attribute__((packed));

int main(int argc, char** argv)
{
    printf("%d:%d\n", sizeof(struct SkipListNode), sizeof(struct SkipListNode_pack));
    return 0;
}
#包括 结构SkipListNode{ void*data;//8字节 uint8\u t size;//1字节 无效*下一个[1]; }; 结构SkipListNode\u包{ void*data;//8字节 uint8\u t size;//1字节 无效*下一个[1]; }_uuu属性_uuu((压缩)); int main(int argc,字符**argv) { printf(“%d:%d\n”、sizeof(struct SkipListNode)、sizeof(struct SkipListNode_pack)); 返回0; }
上述代码的输出:
ishaypeled@arania沙盒]$。/测试

24:17

所以是的,如果你想节省内存,你一定要在你的例子中使用
\uuuuuuu属性((打包))
。另一方面,就像@MarioTheSpoon所说的那样,它可能会带来性能上的损失


我会检查填充解决方案,看看你是否能在特定的机器上承受这种惩罚。我敢打赌,除非你真的非常注重性能,否则你不会注意到它。

我接受了另一个答案

然而,我确实考虑过程序的重构,我找到了一种在不知道数组大小的情况下正确进行的方法

如果有人对此感兴趣,请点击:

因此,我消除了
size
字段,并消除了end NULL。现在结构已对齐:)


在重构时,我记得可以使用
malloc\u-available\u-size()
来查找分配块的大小。这是一种严重的不可移植攻击,但在其他情况下可能会很好地工作。

您是否考虑过
#pragma pack(1)
以确保不同编译器的打包结构编译器指令不同。请指定有问题的编译器。@Nick这是正确的,但我认为操作系统在管理自身资源方面有一定的优势。当您使用packed时,实际尺寸应为该结构可能的最小尺寸。我相信malloc级别中的额外填充不会浪费(想想这样做的后果吧!),而是被重新用于进一步的malloc调用。无论如何,它很容易测试。。。只要用1000个结构运行您的进程,看看它消耗了多少内存。在你写自己的之前最好先写allocator@Ishay:解包结构中的内存将被浪费。它的添加使得变量位于机器字的“偶数”边界上(现在通常为64位)。如果你把它打包,这通常用于跨机器边界传输,因为只有到那时才知道真正的结构,VAR一个接一个地紧紧地坐着。这意味着,当您加载它们时,将有(afaik)额外的操作来进行排序。所以请注意,您正在用内存换取CPU。只有在非常非常必要的情况下才能进行打包。@Lundin:不,它不支持灵活的成员,这就是为什么大小是1而不是0或只是[]。但代码运行得很好,分配时只需记住这一点。这甚至适用于POD类。我不同意!仅在确实必要时使用#pragma pack(1)。在一台标准计算机上浪费大约10万的标准程序不应该是最令人担忧的。当然,如果它是某种嵌入式系统,或者您正在分配数百万条这样的记录,那么推理可能会有所不同。系统再次欺骗您,因为malloc将再次对齐64位边界上的缓冲区(在所描述的系统上)。您根据OP的
struct
指定
next
成员有什么特殊原因吗?@mariothspoon此问题的动机是为了节省内存。。。我已经同意这可能会导致CPU折衷,但这正是作者所要求的……这里有一个关于CPU惩罚的有趣讨论: