Как создать функцию, которая принимает параметр неизвестного типа В C?

скажем, у меня есть следующий код:

struct test* t1;
t1 = get_t(1);

... где get_t - это:

struct test* get_t(int);

как я могу переработать этот код и поместите его в функцию? Что-то вроде следующего:

void r1(?* t, ?* (fn*)(int)) {
    t = fn(1);
}

/* ... */

struct test* t1;
r1(t1, &get_t);

3 ответов


использовать void *param указатель на что угодно ... обычно используется в glib как gpointer


у меня есть две идеи:

[1] передают void указатель на переменную / объект и введите cast it в функции.

[2] Сделайте объединение всех типов данных вместе с целочисленным типом данных, который определит, какая переменная типа данных в объединении содержит фактические данные. Передайте это объединение как значение или как void *

struct _unknown {
   union {
      int a;
      float b;
      char c;
      double d;
   } data;
   int type;
} unknown;
.
.
.
if (unknown.type == FLOAT)
{
  /* Process variable b */ 
}
else if (unknown.type == INT)
{
 /* Process variable a */
}
.
. 
.

что-то вроде этого.

вы можете хэш определения FLOAT и INT и другие как уникальные значения.

или просто

struct _unknown {
  void *data;
  int type;
} unknown;
.
.
.
if (unknown == FLOAT)
{
  /* process (float *) data */
}
else if (unknown == INT)
{
  /* process (int *) data */
}
else if (unknown == MY_DATA_TYPE)
{
  /* process (my_data_type *) data */
  /* where my_data_type could be a typedef, or struct */
}

если у вас есть gcc, вы можете использовать эту более безопасную версию:

#define r1(varp,func) ({ \
    typeof(**varp)* (*_func_)(int); \
    typeof(**varp)* _varp_ = (varp); \
    _func_ = (func); \
    r1_((void**)(_varp_),(void*(*)(int))_func_); \
    })

void r1_(void** varp,void*(*func)(int))
    {
    *varp = func(1);
    }

вызовы так:

struct test* get_t(int);
struct test* t1;
r1(&t,get_t);

(вам не нужно использовать & на функции, они распадаются на указатели автоматически, как массивы). Это проверяет, что t является указателем, и это get_t является функцией, возвращающей этот тип указателя. _varp_ технически не требуется, но сохраняет оценку аргумента в правильном порядке.

Edit:

если у вас нет gcc, вы все еще можете сделайте это, но вы должны явно указать тип:

#define r1(T,varp,func) do { \
    T*(*_func_)(int); \
    T* _varp_ = (varp); \
    _func_ = (func); \
    r1_((void**)(_varp_),(void*(*)(int))_func_); \
    } while(0)

void r1_(void** varp,void*(*func)(int))
    {
    *varp = func(1);
    }

вызовы так:

struct test* get_t(int);
struct test* t1;
r1(struct test*,&t,get_t);

не совсем так безопасно и более избыточно, но все же довольно хорошо.