如何将“类型”作为参数传递给 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 的建议,因为它提供了类型安全。
我想编写通用函数(例如,函数获取 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 的建议,因为它提供了类型安全。