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个字节的浪费。我可以完全删除大小字段,但是我应该在数组末尾保留singleNULL
(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惩罚的有趣讨论: