3

在一个简单的列表中,例如:

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 */

节点和数据将被一次性删除,因此将它们紧密耦合没有真正的问题(按设计)

我正在查看可移植性问题(特别是包装问题)或其他未知问题?

这种分配方式安全便携吗?

4

4 回答 4

4

正如 dirkgently 所说,不要malloc()在 C 中返回,这样做是没有用的,并且可以隐藏错误。

此外,为了计算 Node 标头之后的地址,我发现这样做更简洁:

t->data = t + 1;

这是有效的,因为t它是一个类型化的指针,所以它的算术工作正常。加一会使它增加指向数据的大小,即sizeof (Node)在这种情况下。对于这种特殊情况,我发现这种用法习惯用法,即在刚编辑的东西之后立即计算地址malloc()(当那个“东西”是一个具有静态已知大小的明确定义的类型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;
}

而已。注意在调用中sizeof指针目标malloc()的使用,以避免重复类型名称并在类型应该改变时产生易于忘记的依赖关系。

于 2009-04-03T08:03:30.337 回答
3

从技术上讲,如果数据有对齐要求,这可能是不安全的。malloc() 返回一个适合所有类型对齐的指针,并且很可能t+1也对齐。可能,但不能保证。

于 2009-04-03T08:37:47.727 回答
2

Node在创建别名之前,您不能将其用作类型。利用:

typedef struct Node {
   struct Node* n;
   void* data;
}Node;

malloc如果您要坚持使用 C 编译器,则无需强制转换结果。我发现以下内容更易于维护和阅读:

Node* t = malloc(sizeof *t + DataSize);

BYTE不是语言定义的标准类型,因此不可移植。以下行试图完成什么?

t->data = (BYTE*)t+ sizeof(Node); 

如果你想分配一些东西,以下就足够了:

t->data = pointer to some data ...

如果要获取字节偏移量,请使用offsetof宏。

打包是特定于实现的。您必须参考适当的编译器文档并查看可用的内容。

此外,您可能希望有一个head对象来维护有关列表的一些内务信息(长度等)。

于 2009-04-03T07:59:19.237 回答
1

我同意@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)。

于 2009-04-03T12:13:07.943 回答