即使可以使用void指针(泛型指针)在C中编写通用代码,我发现调试代码非常困难,因为void指针可以在没有编译器警告的情况下采用任何指针类型。 (例如,函数foo()取空指针,它应该是指向struct的指针,但是如果传递了char数组,编译器就不会抱怨。) 在C中使用void指针时,你们都使用什么样的方法/策略?
答案 0 :(得分:8)
解决方案不是使用void*
,除非你真的,真的必须这样做。实际需要void指针的地方非常小:线程函数的参数,以及需要通过泛型函数传递特定于实现的数据的少数其他地方。在每种情况下,接受void*
参数的代码只应接受通过void指针传递的一个数据类型,并且类型应记录在注释中,并且所有调用者都会盲目地遵守。< / p>
答案 1 :(得分:4)
这可能会有所帮助:
comp.lang.c FAQ list · Question 4.9
问:假设我想编写一个将泛型指针作为参数的函数,我想模拟通过引用传递它。我可以给出形式参数类型void **,并做这样的事情吗?
void f(void **);
double *dp;
f((void **)&dp);
答:不便携。像这样的代码可能有效并且有时会被推荐,但它依赖于具有相同内部表示的所有指针类型(这是常见的,但不是通用的;请参阅问题5.17)。
C中没有通用的指向指针类型.void *仅作为通用指针使用,因为当其他指针类型与void *分配时,会自动应用转换(如果需要);如果尝试间接在指向void *之外的指针类型的void **值上,则无法执行这些转换。当您使用void **指针值时(例如,当您使用*运算符访问void **指向的void *值时),编译器无法知道该void *值是否为一次从其他指针类型转换而来。它必须假设它只不过是一个空洞*;它无法执行任何隐式转换。
换句话说,你玩的任何void **值必须是某个地方的实际void *值的地址;像(void **)&amp; dp这样的演员虽然可以关闭编译器,但是不可移植(甚至可能不能做你想做的事情;另见问题13.9)。如果void **指向的指针不是void *,并且它的大小或表示形式与void *不同,那么编译器将无法正确访问它。
要使代码片段在上面工作,你必须使用一个中间的void *变量:
double *dp;
void *vp = dp;
f(&vp);
dp = vp;
vp的分配使编译器有机会在必要时执行任何转换。
同样,到目前为止的讨论假设不同的指针类型可能具有不同的大小或表示,这在今天很少见,但并非闻所未闻。为了更清楚地理解void **的问题,将情况与一个类似的情况进行比较,比如说int和double类型,它们可能有不同的大小,当然也有不同的表示形式。如果我们有一个功能
void incme(double *p)
{
*p += 1;
}
然后我们可以做类似的事情
int i = 1;
double d = i;
incme(&d);
i = d;
并且我将增加1.(这类似于涉及辅助vp的正确的void **代码。)另一方面,如果我们尝试类似
的话int i = 1;
incme((double *)&i); /* WRONG */
(此代码类似于问题中的片段),它不太可能工作。
答案 2 :(得分:2)
Arya的解决方案可以稍微改变以支持可变大小:
#include <stdio.h>
#include <string.h>
void swap(void *vp1,void *vp2,int size)
{
char buf[size];
memcpy(buf,vp1,size);
memcpy(vp1,vp2,size);
memcpy(vp2,buf,size); //memcpy ->inbuilt function in std-c
}
int main()
{
int array1[] = {1, 2, 3};
int array2[] = {10, 20, 30};
swap(array1, array2, 3 * sizeof(int));
int i;
printf("array1: ");
for (i = 0; i < 3; i++)
printf(" %d", array1[i]);
printf("\n");
printf("array2: ");
for (i = 0; i < 3; i++)
printf(" %d", array2[i]);
printf("\n");
return 0;
}
答案 3 :(得分:1)
方法/策略是最小化void *指针的使用。在特定情况下需要它们。如果你真的需要传递void *,你也应该传递指针目标的大小。
答案 4 :(得分:0)
这个通用交换函数将帮助您理解通用void *
#include<stdio.h>
void swap(void *vp1,void *vp2,int size)
{
char buf[100];
memcpy(buf,vp1,size);
memcpy(vp1,vp2,size);
memcpy(vp2,buf,size); //memcpy ->inbuilt function in std-c
}
int main()
{
int a=2,b=3;
float d=5,e=7;
swap(&a,&b,sizeof(int));
swap(&d,&e,sizeof(float));
printf("%d %d %.0f %.0f\n",a,b,d,e);
return 0;
}
答案 5 :(得分:-2)
我们都知道C类型系统基本上是垃圾,但是尝试不这样做......你仍然有一些处理泛型类型的选项:联合和不透明指针。
无论如何,如果泛型函数将void指针作为参数,它不应该尝试取消引用它!。