Как правило, используются специальные функции, подобные приведенным ниже.
void List_Put_int(list *L, int *i);
void List_Put_double(list *L, double *d);
int * List_Get_int(list *L);
double *List_Get_double(list *L);
В не очень простом для учащихся подходе используется _Generic
. C11 предлагает _Generic
, который позволяет управлять кодом во время компиляции по желанию в зависимости от типа.
Ниже приведен базовый код для сохранения/выборки до 3 типов указателей. Макросы потребуют расширения для каждого нового типа. _Generic
не допускает перечисления 2 типов, которые могут быть одинаковыми, например unsigned *
и size_t *
. Так что есть ограничения.
Макрос type_id(X)
создает перечисление для 3 типов, которые можно использовать для проверки наличия проблем во время выполнения, как с LIST_POP(L, &d);
ниже.
typedef struct node {
void *data;
int type;
} node;
typedef struct list {
node *head;
node *tail;
} list;
node node_var;
void List_Push(list *l, void *p, int type) {
// tbd code - simplistic use of global for illustration only
node_var.data = p;
node_var.type = type;
}
void *List_Pop(list *l, int type) {
// tbd code
assert(node_var.type == type);
return node_var.data;
}
#define cast(X,ptr) _Generic((X), \
double *: (double *) (ptr), \
unsigned *: (unsigned *) (ptr), \
int *: (int *) (ptr) \
)
#define type_id(X) _Generic((X), \
double *: 1, \
unsigned *: 2, \
int *: 3 \
)
#define LIST_PUSH(L, data) { List_Push((L),(data), type_id(data)); }
#define LIST_POP(L, dataptr) (*(dataptr)=cast(*dataptr, List_Pop((L), type_id(*dataptr))) )
Пример использования и вывод
int main() {
list *L = 0; // tbd initialization
int i = 42;
printf("%p %d\n", (void*) &i, i);
LIST_PUSH(L, &i);
int *j;
LIST_POP(L, &j);
printf("%p %d\n", (void*) j, *j);
double *d;
LIST_POP(L, &d);
}
42
42
assertion error
person
chux - Reinstate Monica
schedule
21.06.2017
0
оценивает нулевой указатель любого типа, как и(void *)0
... но что касается более четкого вопроса в комментарии к вашему коду: Не совсем, вам нужно придумать собственное решение (например,enum
для типов, которые вы используете). Информация о типе в C больше не существует после компиляции, поэтому нет объекта типа типа. - person   schedule 21.06.2017void list_put_int(list *L, int *p) { .... xx.data = p; ...}
иint *list_get_int(list *L) { .... return xx.data;}
еще как @Felix Palmen сказал, что нет объекта типа типа и нет приведения, которое изменяется во время выполнения (кроме, возможно, VLA, и это все равно здесь не поможет). - person chux - Reinstate Monica   schedule 21.06.2017_Generic
с макросом для достижения большей части цели. Это немного запутанно. - person chux - Reinstate Monica   schedule 21.06.2017