如何将“类型”作为参数传递给 c 中的函数?

How can I pass a “Type” as a argument to function in c?

我想编写通用函数(例如,函数获取 void** 类型的数组并对这个数组做一些事情)这样这个函数将获取元素的类型(在这个例子中,它将是数组中任何元素的类型)作为参数。

我可以用 c 实现吗?


例如:

我想编写一个函数来获取数组(类型为 void**)并以某种随机方式初始化该数组。

"in some random way" 我的意思是,例如一个函数作为参数获取:数组(类型 void**),数组中任何元素的类型、索引(类型为 int)并初始化此单元格。

这只有在您拥有标准 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

你没有通过"type"。 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 的建议,因为它提供了类型安全。