[英]generic programming in C with void pointer
尽管可以使用void指针(泛型指针)在C中编写通用代码,但我发现调试代码非常困难,因为void指针可以在没有编译器警告的情况下采用任何指针类型。 (例如,函数foo()接受void指针,它应该是指向struct的指针,但是如果传递char数组,编译器不会抱怨。)在C中使用void指针时,你们都使用什么样的方法/策略?
解决方案不是使用void*
除非你真的,真的必须。 实际需要void指针的地方非常小:线程函数的参数,以及需要通过泛型函数传递特定于实现的数据的少数其他地方。 在每种情况下,接受void*
参数的代码应该只接受通过void指针传递的一种数据类型,并且类型应该记录在注释中并且被所有调用者盲目地遵守。
这可能有所帮助:
问:假设我想编写一个将泛型指针作为参数的函数,我想模拟通过引用传递它。 我可以给出形式参数类型void **,并做这样的事情吗?
void f(void **);
double *dp;
f((void **)&dp);
答:不便携。 像这样的代码可能有效并且有时会被推荐,但它依赖于具有相同内部表示的所有指针类型(这是常见的,但不是通用的;请参阅问题5.17)。
C中没有通用的指向指针类型.void *仅作为通用指针使用,因为当其他指针类型与void *分配时,会自动应用转换(如果需要); 如果尝试间接在指向void *之外的指针类型的void **值上,则无法执行这些转换。 当您使用void **指针值时(例如,当您使用*运算符访问void **指向的void *值时),编译器无法知道该void *值是否为一次从其他指针类型转换而来。 它必须假设它只不过是一个空洞*; 它无法执行任何隐式转换。
换句话说,您使用的任何void **值必须是某个地方的实际void *值的地址; 类似于(void **)和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 */
(此代码类似于问题中的片段),它不太可能工作。
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;
}
方法/策略是最小化void *指针的使用。 在特定情况下需要它们。 如果你真的需要传递void *,你也应该传递指针目标的大小。
这个通用交换函数将帮助您理解通用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;
}
我们都知道C类型系统基本上是废话,但是尽量不这样做......你仍然有一些选项来处理泛型类型:联合和不透明指针。
无论如何,如果泛型函数将void指针作为参数,它不应该尝试取消引用它!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.