<template> замена для связанного списка C - PullRequest
3 голосов
/ 09 февраля 2010

Только что закончил небольшой связанный список в C и понял, что у меня проблема. Для C нет шаблонных аргументов, поэтому в начале файла я объявляю свой тип данных для списка, что-то вроде:

typedef int LData;

Пока все хорошо, но я не могу использовать этот связанный список для 2 (или более) разных типов данных в одной программе.

Я могу определить LData как void* и вручную преобразовать его в определенный тип данных в соответствии с контекстом. Но мне интересно, есть ли более элегантные решения?

Ответы [ 5 ]

2 голосов
/ 09 февраля 2010

Определите ваш тип LData как void*. Пользователь связанного списка должен знать, какие данные он содержит, чтобы он мог приводить к void* и обратно, когда он вводит или выводит данные.

1 голос
/ 09 февраля 2010

union был изобретен для этой цели, хотя это не очень безопасная конструкция.

0 голосов
/ 09 февраля 2010

Когда я хочу использовать обобщенный набор кода связанного списка (или, в моем случае, очереди), я встраиваю указатель связанного списка в более крупную структуру, с которой я хочу его использовать. Затем используйте имя поля ссылки при передаче аргументов функциям связанного списка. И есть функция, которая может преобразовывать указатель связанного списка в более крупный указатель структуры, когда я получаю указатели из моего связанного списка. Что-то вроде кода, который вы видите ниже.

Эта идиома не дает вам безопасности типов C ++, но код довольно чистый, с приведением типа локализации к нескольким функциям.

// some representative bits of my linked list API
//
typedef void* PLINK;

extern PLINK LLAddToList(PLINK head, PLINK new);
extern PLINK LLNextItem(PLINK current); 

// the structure I want to use it with

typedef struct _foo {
   PLINK  pLink;
   int    data1; 
   int    data2;
} FOO;

// to allow for the link pointers to be some other than the first field
// we use this to go from link pointer to structure pointer.
FOO * FooFromPLink(PLINK current) {
    return (FOO *)((char *)&current - FIELD_OFFSET(FOO, pLink));
}

void MyFunction()
{
   // this idiom to use the linklist code with a FOO struct
   //
   FOO * pfoo = // allocate and initialize a foo
   LLAddToList(head, &pfoo->pLink);


   // this idiom to traverse a list of FOOs, etc.
   //
   PLINK next = LLNextItem(head);
   while (next)
      {
      pfoo = FooFromPLink(next);
      // operate on foo.
      next = LLNextItem(next);
      }

}
0 голосов
/ 09 февраля 2010

У вас может быть куча #defines, определяющих тип, хранящийся в "ссылке"?

т.

 #define TYPE_INT   0
 #define TYPE_FLOAT 1
 // etc

Затем определите каждую запись как-то так:

 struct LinkedListLink
 {
      int    type;
      LData  data;
 };

Теперь, проверив «тип», вы узнаете, какие данные были добавлены (при условии, что вы установили их соответствующим образом при настройке структуры LinkedListLink).

0 голосов
/ 09 февраля 2010

Или используйте непрозрачную идиому указателя:

struct datum;
typedef struct datum datum;
typedef datum *LData;

struct datum {
   int whatever;
};
...