LINUX.ORG.RU

Реализация generic списков в C

 ,


1

2

Написал реализацию списков в Си для одного проекта. изначально мне понадобился функционал списков в более, чем двух местах, но с разными данными.

Реализацию написал такого вида:

typedef struct ListSingly
{
    int64_t              * data;
    struct ListSingly * next;
} ListSingly;

(int64_t * вместо void * из-за того, что void имеет нефиксированный размер)

Вопрос - для generic списка (т.е. когда я в одном месте буду приводить data к float, а в другом к SomeStruct *) такая реализация нормальна? Просто я очень не хочу городить нечитаемый огород из макросов для реализации под каждый конкретный тип.

Как тогда разруливать предупреждения компилятора о том, что типы разного размера, когда, например, я буду использовать signed char для data? Ведь злоупотребление & 0xFF может привести к потере бита знака или его неправильной интерпретации.

★★

Последнее исправление: cetjs2 (всего исправлений: 2)

я очень не хочу городить нечитаемый огород из макросов для реализации под каждый конкретный тип.

Всё уже придумано - man queue

yoghurt ★★★★★
()
Ответ на: комментарий от sambist

Вообще-то sizeof (int64_t *) тебе должен то же самое показать :)

yoghurt ★★★★★
()
Ответ на: комментарий от sambist

Не так уж много там магии (foreach что еще?), а проблемы появляются только когда один объект должен одновременно находится в разных списках.

amaora ★★
()

Тред не читал.

Написал реализацию списков в Си для одного проекта. изначально мне понадобился функционал списков в более, чем двух местах, но с разными данными.

А зачем тебе «списки»?

(int64_t * вместо void * из-за того, что void имеет нефиксированный размер)

Да ты ещё и нулёвый. Ты наверное перепутал размер указателя и размер разименуемых данных, воид не имеет длинны данных - он не разименовывается.

Просто я очень не хочу городить нечитаемый огород из макросов для реализации под каждый конкретный тип.

Ну судя по твоему перлу чуть выше, проблема далеко не в «нечитаемости макросов».

Как тогда разруливать предупреждения компилятора о том, что типы разного размера, когда, например, я буду использовать signed char для data? Ведь злоупотребление & 0xFF может привести к потере бита знака или его неправильной интерпретации.

man union.

Carb_blog2
()

ах да, забыл и ушел без макросов:

typedef union {
  int32_t int32;
  uint32_t uint32;
  int64_t int64;
  uint64_t uint64;
  double dbl;
  float flt;
  void * vptr;
} data_t;

typedef struct node {
  struct node * next;
  data_t data;
} node_t;

#define T_to_data(T) ({(data_t)T;})
#define data_to_T(data, T) ({\
  typeof(T) __test_decl;\
  (typeof(data))__test_decl;\
  *(typeof(T) *)&(data);\
})

Юзать как-то так:

  node_t * node = memcpy(malloc(sizeof(node_t)), &(node_t){123, T_to_data(123.f)}, sizeof(node_t));
  fprintf(stderr, "%lu, %f\n", node->next, data_to_T(node->data, float));

Вобщем идея понятна. Оно проверяет типы, если ты заюзаешь T_to_data и data_to_T не с теми типами, то будет ошибка.

Carb_blog2
()
Ответ на: комментарий от crowbar

Не спорь с царём, его код божественнен. Похоже, он пытается ужать всю доступную человеку сложность в одну-две страницы.

i-rinat ★★★★★
()

Там, где нужен си, не нужны обобщенные списки. Макросов из sys/queue.h может быть достаточно в крайнем случае. А вообще, в си не стоит так обобщать. Возьми C++ и не подпрыгивай.

anonymous
()

если функция может вернуть ошибку то ошибка должна быть обработана. все кто не обрабатывают возможную ошибку - писатели анекдотов на C.

quest ★★★★
()
Ответ на: комментарий от runtime

Но void* может быть недостаточного размера, чтобы вмещать указатель на функцию... Но на почти всех нормальных платформах всё будет хорошо.

vzzo ★★★
()
Ответ на: комментарий от i-rinat

оО, убожество уже настучало. Ты когда жть стучать начало? Сразу или попозже?

P.S. Эй, обезьяна которая меня забанила, ты же мне осилишь с пруфцами показать «4.3 Провокация flame»? Это сборище крыс меня так веселит - одна стучит, другая крыса банит затирая следы. Вы откуда взялись? Как там вам, нравится жрать говно, валяясь в говне? Выж ничтожество пониамете, что банить меня бессмысленно, но зачем вы это делаете? В чем смысл? Потешить крысятскую натуру, что ты что-то можешь?

anonymous
()
Ответ на: комментарий от anonymous

Царь, так чем кроме на NULL проверить можно? Покажи на примере.

deep-purple ★★★★★
()
Ответ на: комментарий от anonymous

if(gh && (p == gh->deviceData)) - это же наверное так не читаемо?

А gcc даёт гарантии, что тут не будет вычислено второе, если первое ложно? Стандарт вот не даёт.

anonymous
()
Ответ на: комментарий от anonymous

Стандарт вот не даёт.

Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated.

i-rinat ★★★★★
()
Ответ на: комментарий от Carb_blog2

воид не имеет длинны данных

в C++. в C имеет, одинаковую с char

jtootf ★★★★★
()
Ответ на: комментарий от vzzo

POSIX добавляет требование равенства размера void * и указателя на функцию.

rand
()

Бери bsd'шный sys/queue.h. Самая вменяемая реализация списков на голом Си.

Reset ★★★★★
()
Ответ на: комментарий от anonymous

Чувак, у тебя очень серьезные проблемы с психикой.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.