safe way of allocating memory for a list node

冷暖自知 提交于 2019-12-10 17:54:51

问题


In a simple list, ex :

struct Node {  
    Node *next;  
    void *data;  
}  

is there any problem if i allocate Node and Data in a single allocation (provided i know the size), like

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

and always assign data at the end of allocated chunk,

t->data = (BYTE*)t+ sizeof(Node); /* BYTE is byte length, can use char in gcc */

Node and data will get deleted in a sinlge go, so there no real problem tighlty coupling them (by design )

I am looking at Portability issues (specifically with Packing) or other unknown issues ?

Is this way of allocation safe and portable ?


回答1:


As dirkgently said, don't case the return of malloc() in C, doing so is useless and can hide errors.

Also, to compute the address following the Node header, I find it cleaner to do it like this:

t->data = t + 1;

This works because t is a typed pointer, so arithmetic on it works fine. Adding one increments it by the size of the pointed-to data, i.e. sizeof (Node) in this case. I find this usage idiomatic for this particular case, of computing the address immediately following something just malloc()ed (when that "something" is a well-defined type with a statically known size, as the Node struct in this case, of course).

This has the following benefits:

  • No repetition of the type name.
  • No sizeof, so shorter.
  • Again, no cast.
  • Very simple arithmetic involved, easy to read.

I realized there's an error with your use of the Node type before it's properly declared, too. I don't agree with dirkgently's solution, here's how it should look, in 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;
};

For completeness, and since I never tire of showing how I consider code like this should be written, here's an example of a function to create a new node to hold n bytes of data:

Node * node_new(size_t n)
{
  Node *node;

  if((node = malloc(sizeof *node + n)) != NULL)
  {
    node->next = NULL;
    node->data = node + 1;
  }
  return node;
}

That's it. Note use of sizeof on the pointer target in the malloc() call, to avoid repeating the type name and making an easy-to-forget dependency if the type should ever change.




回答2:


Technically, it's could be unsafe if the data has alignment requirements. malloc() returns a pointer suitably aligned for all types, and it's likely that t+1 is also aligned. Likely, but not guaranteed.




回答3:


You cannot use Node as a type until you create an alias. Use:

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

No need to cast the result of malloc if you are going to stick to a C compiler. I find the following easier to maintain and read:

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

BYTE is not a standard type defined by the language and hence unportable. What does the following line try to accomplish?

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

If you want to assign something, the following suffices:

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

If you want to get the byte offset use offsetof macro.

Packing is implementation specific. You have to refer the appropriate compiler documentation and see what is available to you.

Additionally, you may want to have a head object that maintains some housekeeping information about the list (length etc).




回答4:


I agree with @MSalters. As long as you have a level of indirection (the data pointer), you might as well do the proper thing and allocate a separate block for it.

Now, an alternative would be using a flexible array member defined in 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) is supplemented with an appropriate amount of padding (if any) such that the alignment requirements of data are met, and data[] acts as if it was declared as an array of the maximum possible size that would fit the memory block returned by malloc(). This goes for all types of data, not just char (hence the second sizeof).



来源:https://stackoverflow.com/questions/712926/safe-way-of-allocating-memory-for-a-list-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!