C все тип параметра - PullRequest
       22

C все тип параметра

1 голос
/ 02 ноября 2009

Как я могу написать функцию, которая принимает параметр универсального типа в C? (например, int, char ...)

Ответы [ 8 ]

5 голосов
/ 02 ноября 2009

Я бы лично сделал это так:

1) отправить указатель на void * в качестве первого параметра

2) отправьте второй параметр, который скажет вам, что такое пустота * (перечисление возможностей), и приведите параметр 1 к этому

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

Что-то вроде:

// the enum:
BYTE_VALUE = 1; INT_VALUE = 2, CHAR_VALUE = 3 etc

// the function
int parse(void *arg, enum_type arg_type)
{
    if (arg == NULL) return -1;

    switch(arg_type)
    {
    case BYTE_VALUE:
        byte value = (byte) *arg;
        // do work here
    case INT_VALUE:
     // etc
    }

    return something;
}

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

2 голосов
/ 02 ноября 2009

Вы могли бы рассмотреть подход printf. Он передает аргумент, который идентифицирует тип для вызываемой функции.

printf("%d",  intvalue);
printf("%f",  floatvalue);
printf("%s",  stringvalue);

Вот ссылка , которая демонстрирует, как реализовать список переменных аргументов.

2 голосов
/ 02 ноября 2009

Существуют разные методы, все со своими недостатками.

  • Уже упоминалось: используйте указатель void и примените его соответствующим образом. Вы не можете давать значения в качестве аргумента и вам нужно использовать переменную для них:

   myfunc(&7); 

не будет работать, вместо этого:

int x = 7;
myfunc(&x);
  • Уже упоминалось: функции Variadic. Вы должны быть осторожны с преобразованиями по умолчанию и, возможно, должны приводить значения.

  • Использовать объединение в качестве аргумента. Как и в случае с указателем void, вам нужно предварительно установить переменную объединения.

  • Я обычно предпочитаю использовать отдельные функции для разных типов.


void myfuncchar (char c);
void myfuncint (int i);

В зависимости от проблемы, при размещении общих частей в подфункциях обычно не так много дублирования кода.

1 голос
/ 04 ноября 2009

Прошло много времени с тех пор, как я сделал что-то подобное, поэтому проверьте синтаксис.

Чтобы снять ответ Лауры, сделать его более лаконичным:

// the enum:
enum types{ int_val, char_val, float_val };
// the functions

int (*funcArr[3])(void*) = {NULL};


int to_do_if_int(void* input)
{
   return 0;
}

int to_do_if_char(void* input)
{
   return 0;
}

int to_do_if_float(void* input)
{
   return 0;
}

void initializer()
 {
   funcArr[int_val] = &to_do_if_int;
   funcArr[char_val] = &to_do_if_char;
   funcArr[float_val] = &to_do_if_float;
 }

int parse(void *arg, enum_type arg_type){    
   if (arg == NULL) return -1;

   (*funcArr[arg_type])(arg);

   return something;
}
1 голос
/ 02 ноября 2009

Если вы не хотите передавать указатель, вы можете передать объединение. Объявите объединение как структуру, но вы можете использовать только один член за раз. Например:

union foo {
char c;
int i;
}

struct foo f;
f.c = 'd';
function (f);
f.i = 23;
function(f);

int function(union foo f)
...

Помните, что вы можете использовать только одно поле за раз, и если вы установите, например, f.c на что-то, значение f.i изменится потенциально беспорядочно. (Я считаю, что это неопределенное поведение, но если компилятор когда-либо делает что-либо, кроме побайтной замены, он не сможет скомпилировать весь существующий код.) Кроме того, помните, что язык не дает подсказки относительно того, какое поле вы в последний раз изменили так что вам решать как-то это отслеживать.

Это не очень чистое решение, но и не void *. Вы пытаетесь подорвать система типов, и вы не получите хорошего решения.

0 голосов
/ 02 ноября 2009

Лучше всего использовать шаблоны. Вы можете использовать пустые указатели, но это может привести к другим проблемам, если сделано неправильно. Лучше всего пойти ЗДЕСЬ прочитать учебник и попробовать его сами. У вас не должно возникнуть проблем с пониманием концепции шаблонов.

0 голосов
/ 02 ноября 2009

Использование void* - это обычный способ. Посмотрите, например, реализацию memcpy , которая делает именно это - она ​​принимает аргумент любого типа. Вы должны знать, что вам нужно знать исходный тип (то есть тип, приведенный к типу, который изначально имел данные), если вы хотите обрабатывать передаваемые данные «должным образом» (если вы не выполняете реальную обработку, такую ​​как memcpy и т.п. функции), так как передача void* ничего не говорит о контенте - это просто указатель на некоторую память, без какой-либо информации о ее содержании, длине или интерпретации. Таким образом, ваша функция должна обрабатывать это сама, вероятно, с другим параметром, который говорит о типе. memcpy, например, требуется параметр, передающий длину данных в байтах.

0 голосов
/ 02 ноября 2009

То, что вы ищете, называется переменной функцией. Ниже приведена статья в Википедии на эту тему:

http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...