您可以绝对安全地使用void * 将指向任何对象的指针传递给这样的函数。正如其他人所指出的那样,问题在于,一旦进入该函数,您就必须对该对象执行某些操作,并且您需要知道执行该操作的类型,因此即使您不需要该类型要将指针传递给数组,您将需要以某种方式完成任何实际工作。
正如另一个答案所述,您可以使用 C11 泛型来做到这一点,但另一种可能性是不仅传递指向数组的指针,而且还传递指向要在其上执行的代码的指针,使用函数指针。
例如,下面的代码将为任何数值数组的每个元素添加两个(我只为int、long 和double 实现了它,但对于其余的标准数值类型实现它是微不足道的)。 add_two() 函数本身永远不知道它得到的是什么类型的数组。但要实现这一点,您还必须将指针传递给 知道的函数:
#include <stdio.h>
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t));
void add_two_int(void * array, size_t idx);
void add_two_long(void * array, size_t idx);
void add_two_double(void * array, size_t idx);
int main(void)
{
int n[] = {1, 2, 3, 4, 5};
add_two(n, 5, add_two_int);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %d\n", i, n[i]);
}
long l[] = {1L, 2L, 3L, 4L, 5L};
add_two(l, 5, add_two_long);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %ld\n", i, l[i]);
}
double d[] = {1.0, 2.0, 3.0, 4.0, 5.0};
add_two(d, 5, add_two_double);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %f\n", i, d[i]);
}
return 0;
}
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t))
{
for ( size_t i = 0; i < sz; ++i ) {
add_func(array, i);
}
}
void add_two_int(void * array, size_t idx)
{
int * n = array;
n[idx] += 2;
}
void add_two_long(void * array, size_t idx)
{
long * l = array;
l[idx] += 2;
}
void add_two_double(void * array, size_t idx)
{
double * d = array;
d[idx] += 2;
}
带输出:
paul@horus:~/src/sandbox$ ./genarray
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3.000000
1: 4.000000
2: 5.000000
3: 6.000000
4: 7.000000
paul@horus:~/src/sandbox$
当然,在这个简单的示例中,与仅编写 add_two_int() 和朋友并直接使用它们相比,编写 add_two() 函数并没有太多真正的好处。但是在一个更复杂的示例中,例如,您希望在库中拥有类似 add_two() 的内容,那么这是一种无需修改 add_two() 或重建和重建即可处理任意新类型的方法。重新部署您的库。
另外,我将函数命名为add_two(),但显然它只是依次对每个元素执行您提供给它的任何操作。因此,您可以编写函数subtract_two_int(void * array, size_t idx),例如,将其传递给add_two(),它实际上会从每个元素中减去两个,尽管名称不同。