Как я могу передать" тип " в качестве аргумента для функции в 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, поскольку оно обеспечивает безопасность типа.