3

簡単なリストでは、例:

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

Node と Data を 1 回の割り当てで割り当てた場合 (サイズがわかっている場合)、問題はありますか?

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

辛抱強く言ったようにmalloc()、C でのリターンをケースに入れないでください。そうすることは役に立たず、エラーを隠す可能性があります。

また、Node ヘッダーに続くアドレスを計算するには、次のようにする方がクリーンだと思います。

t->data = t + 1;

これtは型付きポインターであるため機能するため、算術演算は正常に機能します。1 を追加すると、ポイント先のデータのサイズだけインクリメントされます。つまりsizeof (Node)、この場合です。この特定のケースでは、この使用法が慣用的であることがわかります。これは、 ed の直後のアドレスを計算することです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;

mallocC コンパイラに固執する場合は、結果をキャストする必要はありません。私は、次のほうが保守と読み取りが簡単だと思います。

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(したがって 2 番目のsizeof)。

于 2009-04-03T12:13:07.943 に答える