Il existe plusieurs approches possibles, dont l'une consiste à stocker un void*
dans votre terminal ADT.
J'ai toujours trouvé que c'est un peu pénible dans une liste chaînée puisque vous devez gérer son allocation séparément à la liste elle-même. En d'autres termes, pour allouer un nœud, vous devez alimenter le nœud et sa charge utile séparément (et n'oubliez pas de les nettoyer tous les deux lors de la suppression).
Une approche que je l'ai utilisé dans le passé est d'avoir une structure « taille variable » comme:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
char payload[1];
} tNode;
Maintenant, cela ne regarder taille variable mais nous allons allouer une structure ainsi:
typedef struct {
char Name[30];
char Addr[50];
char Phone[20];
} tPerson;
tNode *node = malloc (sizeof (tNode) - 1 + sizeof (tPerson));
maintenant vous avez un nœud qui, à toutes fins utiles, ressemble à ceci:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
char Name[30];
char Addr[50];
char Phone[20];
} tNode;
ou, sous forme graphique (où [n]
signifie n
octets):
+------------+
| prev[4] |
+------------+
| next[4] |
+------------+ +-----------+
| payload[1] | | Name[30] | <- overlap
+------------+ +-----------+
| Addr[50] |
+-----------+
| Phone[20] |
+-----------+
qui est, en supposant savez comment traiter correctement la charge utile. Cela peut se faire comme suit:
node->prev = NULL;
node->next = NULL;
tPerson *person = &(node->payload); // cast for easy changes to payload.
strcpy (person->Name, "Richard Cranium");
strcpy (person->Addr, "10 Smith St");
strcpy (person->Phone, "555-5555");
CAST ligne jette simplement l'adresse du être une adresse du type de charge utile tPerson
réelle caractère payload
(dans le type tNode
).
En utilisant cette méthode, vous pouvez transporter tout type de charge utile que vous voulez dans un nœud, même différents types de charge utile dans chaque noeud, si vous faites la structure plus comme:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
int payloadType; // Allows different payload type at each node.
char payload[1];
} tNode;
et utiliser payloadType
pour stocker un indicateur de la charge utile.
Ceci a l'avantage sur une union en ce qu'elle ne gaspille pas d'espace, comme on peut le voir avec les éléments suivants:
union {
int fourBytes;
char oneHundredBytes[100];
} u;
où 96 octets sont gaspillées chaque fois que vous stockez un type entier dans la liste (pour un entier de 4 octets). Le type de charge utile dans le tNode
vous permet de détecter facilement le type de charge utile que ce nœud est en train de transporter, afin que votre code puisse décider comment le traiter. Vous pouvez utiliser quelque chose le long des lignes de:
#define PAYLOAD_UNKNOWN 0
#define PAYLOAD_MANAGER 1
#define PAYLOAD_EMPLOYEE 2
#define PAYLOAD_CONTRACTOR 3
ou (probablement mieux):
typedef enum {
PAYLOAD_UNKNOWN,
PAYLOAD_MANAGER,
PAYLOAD_EMPLOYEE,
PAYLOAD_CONTRACTOR
} tPayLoad;
La seule chose que vous devez surveiller est d'assurer que l'alignement de la charge utile est correcte. Étant donné que mon espace réservé de charge utile et la charge utile sont tous les types char
, ce n'est pas un problème. Cependant, si votre charge utile est composée de types avec des exigences d'alignement plus strictes (comme quelque chose de plus strict que les pointeurs, vous devrez peut-être ajuster pour cela).
Bien que je n'ai jamais vu un environnement avec des alignements plus stricts que les pointeurs, est possible selon la norme ISO C.
Vous pouvez généralement obtenir le simple alignement requis en utilisant un type de données pour l'espace réservé de charge utile qui a l'exigence d'alignement strict tels que:
long payload;
Avec le recul, il me semble que vous avez probablement ne pas besoin un tableau en tant que placeholder de la charge utile. C'est assez simple pour avoir quelque chose dont vous pouvez prendre l'adresse. Je soupçonne que mon idiome particulier remonte à l'époque où je stockais juste un tableau de personnages (plutôt qu'une structure) et les référenciez directement. Dans ce cas, vous pouvez utiliser payload[]
seul sans utiliser un autre type.
Personnellement, j'utilise 'char payload [0]', donc 'sizeof' représente l'en-tête et rien de plus. – strager
Vous expliquez que vous devez lancer la charge utile, mais vous ne faites que la déréférencer dans votre exemple. – strager
Les types de vecteur de 128 bits sur x86 (utilisés par le jeu d'instructions SSE) nécessitent un alignement de 16 octets, par exemple. – zvrba