Как я могу передать" тип " в качестве аргумента для функции в c?
Я хочу написать общую функцию (например, функцию, которая получает массив в типе "void**" и делает что-то с этим массивом), тогда эта функция получит тип элемента (в примере это будет тип любого элемента в массиве) в качестве аргумента.
могу ли я сделать это в c?
например:
Я хочу написать функцию, которая получает массив (в типе void**
) и intialize этот массив в некотором случайном путь.
что означает "каким-то случайным образом" - например, функция, которая получает в качестве аргументов: array (in type void**),тип любого элемента в массиве, index (в типе int) и инициализировать эту ячейку.
4 ответов
это возможно только если у вас есть стандартный компилятор C, в этом случае вы можете использовать _Generic
ключевое слово для этой цели. Вы должны написать другую функцию для каждого поддерживаемого типа.
#include <stdio.h>
#define func(x) _Generic((x), int: func_int, char: func_char)(x);
void func_int (int x)
{
printf("%s\t%d\n", __func__, x);
}
void func_char (char x)
{
printf("%s\t%c\n", __func__, x);
}
int main(void)
{
int i = 5;
char c = 'A';
func(i);
func(c);
}
выход:
func_int 5
func_char A
вы не проходите "тип". C не имеет встроенного способа кодирования и декодирования информации типа во время выполнения. Функция, работающая с объектами, должна знать тип статически. Если вы абсолютно намерены работать с указателями на void
, вы должны делегировать функцию, которая знает информация о типе. Что можно сделать с помощью обратного вызова. Например, стандартная библиотечная функция qsort
принимает обратный вызов для сравнения объектов значения:
void qsort( void *ptr, size_t count, size_t size,
int (*comp)(const void *, const void *) );
вызывающий код поставляет обратный вызов, и внутри указанного обратного вызова он будет отброшен к статическому типу, который ему нужно сравнить. Вот как обычно работает с указателями на void
, один определяет набор операций, которые он должен сделать для типа в абстрактной форме, а затем просит вызывающий код предоставить реализацию для этих операций.
вот пример для некоторых макросов.
func.h
#ifndef FUNC_H
#define FUNC_H
#define add(a, b, typename) functionAdd##typename(a,b)
/* function declarations */
#define declared(typename) \
typename functionAdd##typename(typename, typename)
declared(int);
declared(float);
#endif
func.c
#include "func.h"
/* function code */
#define functionAdd(a, b, typename) \
typename functionAdd##typename(typename a, typename b){ \
return a+b; \
}
/* function bodies (definitions) */
functionAdd(a, b, int)
functionAdd(a, b, float)
main.c
#include <stdio.h>
#include "func.h"
int main()
{
int x1 = add(1, 2, int);
float x2 = add(3.0, 4.0, float);
printf("%d %f\n", x1, x2);
return 0;
}
другим решением может быть определение перечисления для представления типа такой:
#include "stdio.h"
typedef enum {
TYPE_INT,
TYPE_CHAR,
TYPE_STRING
} type_id;
int print(type_id type, void *data) {
switch (type) {
case TYPE_INT:
// Do something with data as int
printf("%d\n", * (int *)data);
break;
case TYPE_CHAR:
// Do something with data as char
printf("%c\n", * (char *)data);
break;
case TYPE_STRING:
// Do something with data as string
printf("%s\n", (char *)data);
break;
}
}
int main() {
int a = 5;
char b = 'a';
char *c = "string";
print(TYPE_INT, &a);
print(TYPE_CHAR, &b);
print(TYPE_STRING, c);
return 0;
}
мне больше нравится предложение Lundin, поскольку оно обеспечивает безопасность типа.