C 内存管理器的不同长度结构?
我练习用C语言实现一个内存管理器 我想要的结构,有不同的长度和自我描述。 所以,我偷看了一本POSIX教科书,比如:C 内存管理器的不同长度结构?,c,memory-management,struct,C,Memory Management,Struct,我练习用C语言实现一个内存管理器 我想要的结构,有不同的长度和自我描述。 所以,我偷看了一本POSIX教科书,比如: struct layout { uint32_t size; // array size in bytes, include space after the struct uchar_t data[1]; }; // But, is next line correct? layout *val = malloc (array_memory_in_bytes + siz
struct layout
{
uint32_t size; // array size in bytes, include space after the struct
uchar_t data[1];
};
// But, is next line correct?
layout *val = malloc (array_memory_in_bytes + sizeof (uint32_t) - 1);
// Where does a static array keep the pointer for using it?
layout *val1 = pointer;
layout *val2 = val1 + val1.size + sizeof (val1.size);
如果在不间断的内存中有几个这样的结构,我希望能够遍历它们。我能写点什么吗
struct layout
{
uint32_t size; // array size in bytes, include space after the struct
uchar_t data[1];
};
// But, is next line correct?
layout *val = malloc (array_memory_in_bytes + sizeof (uint32_t) - 1);
// Where does a static array keep the pointer for using it?
layout *val1 = pointer;
layout *val2 = val1 + val1.size + sizeof (val1.size);
或者你能给我推荐一种更好的方法吗?这种方法的标准C版本称为flexible array member,它看起来像:
struct layout
{
uint32_t size;
uchar_t data[];
};
// allocate one of these blocks (in a function)
struct layout *val = malloc( sizeof *val + number_of_bytes );
val->size = number_of_bytes;
代码
val1->data+val1->size
将为您获取一个指针,该指针将越过刚刚malloc
'd的空间末端
但是,您不能迭代一个malloc
'd块的末尾,而希望命中另一个malloc
'd块。要实现这个想法,您必须malloc
一个大的块,然后在其中放置各种struct layout
对象,要小心
在这种方法中,最好还存储每个结构布局所在位置的索引。理论上,你可以每次从一开始就查看列表,添加大小
,然后进行对齐调整;但这将是缓慢的,这也意味着你无法应付中间的一个块被释放和重新“分配”。
如果这是对malloc
的替代,那么实际上有两个对齐注意事项:
- 结构布局的对齐
数据
必须与任何可能的类型对齐
处理此问题的最简单方法是对齐任何可能类型的struct layout
。这可能看起来像(注意:#包括
必填项):
另一种方法是将大小保持在32位,并加入杂注包以防止填充;然后,您需要使用一些额外的复杂度来确保结构布局
在max\u align\t
字节边界之前放置4个字节,以此类推。我建议先用简单的方法完成,然后让代码运行;然后,如果需要,您可以返回并尝试此更改以节省一些字节的内存
备选办法:
- 将
结构布局的每个实例及其尾部数据保留在单独的分配中李>
- 将
数据
更改为指向malloc
'd空间的指针;然后可以将所有结构布局
对象保留在一个数组中
总体思路可行,但只有在最严重的边界对齐情况是int的情况下,特定结构才会起作用
内存管理器,特别是可能是malloc()
实现的后端的内存管理器,必须知道最坏情况的边界是什么。数据的实际开始必须在该边界上,以满足分配的内存对任何数据类型的存储进行适当对齐的一般要求
最简单的方法是使布局
结构描述的长度分配头和实际分配大小都是该对齐单元的倍数
不管怎样,您都不能将数据的开头描述为一个结构成员,而将该结构的大小设置为头的大小。C不支持零长度字段。您应该使用一些东西将该数组置于边界上,并使用
中的offsetof()
宏
P>个人,我将使用 CuthOng/Cuth>,基于C语言的旧习惯和偶尔使用Visual C++,但是UTIN 32是一个C99类型,如果你还有C11支持,你可以使用。这样,您的结构可以看起来像:
#define ALIGN_TYPE double /* if this is the worst-case type */
#define ALIGN_UNIT ((sizeof)(ALIGN_TYPE))
#define ALIGN_SIZE(n) (((size_t)(n) + ALIGN_UNIT - 1) & ~(ALIGN_UNIT-1))
typedef struct layout
{
size_t size; /* or use uint32_t if you prefer */
_Alignas(ALIGN_UNIT) char data[1];
} layout;
#define HEADER_SIZE (offsetof(layout, data))
这使得除最坏情况下的对齐类型外的所有内容都具有象征性。您将使用以下各项分配组合的标头加数据数组:
layout *ptr = (layout*) malloc(HEADER_SIZE + ALIGN_SIZE(number_of_bytes));
ptr->size = HEADER_SIZE;
但是,除非C99/C11更改了sizeof
的定义,否则ALIGN\u SIZE类型实际上不是一个符号常量。例如,不能使用计算普通数组维度。如果有问题的话,你可以硬编码一个文字数字,比如8代表一个典型的双精度数字。请注意,在许多x86实现中,longdouble
的大小有问题(10字节)。如果要根据类型来确定分配单位,则long double
可能不是最佳选择。似乎相当合理,但您可能希望/需要在对象之间添加对齐。如果您有C99编译器,请使用灵活的数组成员。根据平台的不同,您可能需要考虑“大小”和“数据”之间的填充。如果可以,您应该明确定义结构的打包,以确保没有任何额外空间。@doynax,感谢您使用“灵活数组成员”一词,我找到了我问题的答案@joshpoley,行“struct layout val=malloc(sizeof*val+(字节数-1));/non-flexible*/”不依赖于打包方式关于“静态数组在哪里保存指针以供使用?”,它不依赖于打包方式。这样的指针是根据需要创建的右值。如果这样做,必须考虑对齐:每个结构应在4字节边界上对齐,以便正确对齐uint32\t size
成员。要么将大小保持为4的倍数,要么在结构之间添加一些额外的填充。@因此实际问题是数据中的字节数可能不是对齐的倍数;因此,在放置另一个struct layout
@之前,您必须插入一些填充字节。因此,olitary:使用sizeof(struct layout)
实际上无助于对齐,因为您添加数组长度时没有对齐它。这实际上让事情变得更糟,因为在C99之前的版本中,struct header
在1字节数组之后包含3字节的填充。您应该使用偏移量(结构布局、数据)+align4(字节数)
来定义此定义