为列表节点分配内存的安全方法
在一个简单的列表中,ex:
struct Node { Node *next; void *data; }
如果我在一个分配中分配节点和数据(如果我知道大小),有什么问题,比如说
Node * t = (Node*)malloc(sizeof(Node) + DataSize));
并始终在分配的块的末尾分配数据,
t->data = (BYTE*)t+ sizeof(Node); /* BYTE is byte length, can use char in gcc */
节点和数据将在sinlge go中删除,因此没有真正的问题紧密耦合它们(按设计)
我正在研究可移植性问题(特别是包装)或其他未知问题?
这种分配方式安全便携吗?
正如dirkgently所说,不要假设在C中返回malloc()
,这样做是没用的,可以隐藏错误。
另外,为了计算Node标头后面的地址,我觉得它更清晰,就像这样:
t->data = t + 1;
这是有效的,因为t
是一个类型指针,因此对它的算术工作正常。 添加一个以指向数据的大小递增它,即在这种情况下sizeof (Node)
。 我发现这种用法惯用于这种特殊情况,即紧接着malloc()
ed之后的地址计算地址(当“某些东西”是具有静态已知大小的明确定义的类型时,在本例中为Node
结构,当然)。
这有以下好处:
- 不重复类型名称。
- 没有
sizeof
,所以更短。 - 再一次,没有演员。
- 涉及非常简单的算术,易于阅读。
我意识到在正确声明之前使用Node
类型时出现错误。 我不同意dirkgently的解决方案,这是它的外观,在C中:
/* This introduces the type name "Node", as an alias for an undefined struct. */ typedef struct Node Node; struct Node { Node *next; /* This is OK, the compiler only needs to know size of pointer. */ void *data; };
为了完整性,因为我从不厌倦地展示我应该如何编写这样的代码,这里是一个创建一个新节点来保存n个字节数据的函数示例:
Node * node_new(size_t n) { Node *node; if((node = malloc(sizeof *node + n)) != NULL) { node->next = NULL; node->data = node + 1; } return node; }
而已。 注意在malloc()
调用中对指针目标使用sizeof
,以避免重复类型名称并在类型应该更改时产生易于忘记的依赖关系。
从技术上讲,如果数据具有对齐要求,则可能不安全。 malloc()返回一个适合所有类型的指针,很可能t+1
也是对齐的。 可能,但不保证。
在创建别名之前,不能将Node
用作类型。 使用:
typedef struct Node { struct Node* n; void* data; }Node;
如果要坚持使用C编译器,则无需转换malloc
的结果。 我发现以下更容易维护和阅读:
Node* t = malloc(sizeof *t + DataSize);
BYTE
不是语言定义的标准类型,因此不可移植 。 以下行尝试完成什么?
t->data = (BYTE*)t+ sizeof(Node);
如果你想分配一些东西,以下就足够了:
t->data = pointer to some data ...
如果要获取字节偏移量,请使用offsetof
宏。
包装是特定于实施的。 您必须参考相应的编译器文档并查看可用的内容。
此外,您可能希望有一个head
对象来维护有关列表的一些内务信息(长度等)。
我同意@MSalters。 只要你有一个间接级别( data
指针),你也可以做正确的事情并为它分配一个单独的块。
现在,另一种方法是使用C99中定义的灵活数组成员 :
typedef struct Node { struct Node *next; char data[]; } Node; Node *n = malloc(sizeof(*n) + DataSize * sizeof(*data)); //if (n != NULL), access data[0 ~ DataSize-1]
sizeof(struct Node)
补充了适当数量的填充(如果有的话),以便满足data
的对齐要求,而data[]
就好像它被声明为一个适合内存的最大可能大小的数组malloc()
返回的块。 这适用于所有类型的data
,而不仅仅是char
(因此是第二个sizeof
)。