2015-12-21 3 views
0

Это не как «Как смешанный тип данных (int, float, char и т. Д.) Должен храниться в массиве?» вопрос внимательно прочитайте пожалуйста! Предположим, у меня есть следующий пустой указатель, то я не знаю, что это тип до выполнения:Как нарисовать указатель void во время выполнения на C, таким образом, который можно использовать в остальном коде?

void* data; 

теперь я знаю, что я могу сделать следующее, когда я знаю, тип data (например int):

int typed_data = *(int*)data; 

используя switch case заявление, которое я мог бы проверить переменную, чтобы определить, какие ввергнуть выполнять:

switch(type_id) { 
    case INT: 
     int typed_data = *(int*)data; 
     break; 
    case FLOAT: 
     float typed_data = *(float*)data; 
     break; 
    // ... 
    // etc. 
} 

Но, таким образом, я не смогу получить доступ к typed_data за пределами блока switch, рассмотрим приведенный ниже funstion в качестве примера; Она принимает два недействительных указателей, и в соответствии со значением type_id, он бросает s и x исправить типы данных, а затем делает другие вещи с недавно определенными типизированными данными:

int sequential_seach(int n, void* s, void* x, type_id) { 
    int location = 0; 
    switch(type_id) { 
     case INT: 
      int *list = s; 
      int element = *(int*)x; 
      break; 
     case FLOAT: 
      float *list = s; 
      float element = *(float*)x; 
      break; 
      // ... 
      // etc. 
    } 

    while(location < n && list[location] != element) { // <---This will cause a compile error 

     location++; 
     if(location > n - 1) { 
      location = -1; 
     } 
    } 
    return location; 
} 

В приведенных выше функциях location и list не доступен за пределами swtich блока, даже если type_id соответствует одному из case значений и они были определены, они все еще находятся вне сферы, вне switch блока, поэтому, когда компилятор достигает линию while проживает, он жалуется, что location и list не определены. Но эти типизированные переменные необходимы для функции. Итак, как это решить? следует ли скопировать код while в каждый case? Это не выглядит очень хорошим решением. Что делать, если у меня был более длинный код, который нуждался в этих переменных в 100 разных местах?

+2

Похоже, вы хотите другой язык. –

+1

Будет ли «профсоюз» работать на вас? Вы можете сохранить структуру, которая представляет собой пару типов и объединение, которое позволяет вам обращаться к нему как к любому из возможных типов. –

+0

Почему вы это пытаетесь? [tag: c] не подходит для такой системы динамического типа, вы можете попробовать другой язык или другой подход для решения проблемы. Кроме того, как уже упоминалось, «союз» может быть лучшим выбором. Разделение указателей, подобных этому, очень опасно, потому что вы потенциально вызываете неопределенное поведение. –

ответ

-1

Это невозможно бросить пустой указатель во время выполнения в С.

И ваш код не проверяет, если приведение в силе либо. При этом вы либо потеряете некоторые данные, либо рискуете ошибкой сегментации, так как типы данных не имеют одинакового размера.

+0

Хотя ваша точка верна, вопрос был не в проверке. –

+0

Мне кажется, что я отвечаю на вопрос, так как это невозможно сделать. Я просто указываю, что его код не проверяет правильность типа как добавленный комментарий. – loginn

+0

Точка, в которой я не согласен, это «риск возникновения сегментации» *, это не обязательно так. –

1

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

К сожалению, C не имеет в своем роде дженериков. К счастью, you can use macros as pseudo-generics, чтобы препроцессор автоматически генерировал несколько версий вашего кода.

Адаптировано из связанного ответа:

// sequential_search.h 

/* Provide some helpers that generate a name of the form of sequential_search_T, 
    unique for each type argument */ 

#define TOKENPASTE(x, y) x ## y  
#define SEQ_SEARCH(T) TOKENPASTE(sequential_search_, T) 

/* Provide the generic type definition of your function */ 

int SEQ_SEARCH(TYPE) (int n, void* s, void* x) { 
    int location = 0; 
    TYPE* list = s; 
    TYPE element = *(TYPE*)x; 

    while(location < n && list[location] != element) { 
     location++; 
     if(location > n - 1) { 
      location = -1; 
     } 
    } 

    return location; 
} 

Instantiate это один раз для каждого типа аргумента вы намерены передать:

// sequential_search.c 

#define TYPE int 
#include "sequential_search.h" 
#undef TYPE 

#define TYPE float 
#include "sequential_search.h" 
#undef TYPE 

// etc. 

Наконец, создайте (статически разрешимый) место вызова, который будет переключаться на идентификатор типа, который у вас есть (информация о времени выполнения), а затем сразу же отправляется в одну из общих версий:

int sequential_search(int n, void* s, void* x, type_id) { 
    switch(type_id) { 
     case INT: return sequential_search_int(n, s, x); 
     case FLOAT: return sequential_search_float(n, s, x); 
     // etc. 
    } 
} 
+0

Почему я получаю ошибки компилятора в этой строке: 'int SEQ_SEARCH (int n, void * s, void * x)'? Я получаю две ошибки: «Ожидаемый»; после объявления верхнего уровня "и" Слишком много аргументов, предоставляемых функционально-подобному вызову макросов. Также я получаю сообщение об ошибке в строке 'int sequential_search (...)', которая является 'ISO C требует именованного параметра до '...' ' – ilgaar

+0

@igaar Что касается ошибки # 1: см. Редактирование, у меня была опечатка в начальном определении. Что касается ошибки № 2: вы правы, я буквально не имел в виду '...'. Я хотел сказать «предоставить ваши фактические аргументы здесь», но «...» является допустимым синтаксисом C для вариативных функций. См. Редактирование сейчас, оно должно быть более четким. –

+0

Теперь я получаю 'использование необъявленного идентификатора 'TYPE'' в моем заголовочном файле и поэтому' использование незаявленного идентификатора' list'' – ilgaar