繁体   English   中英

C语言中的泛型编程与void指针

[英]generic programming in C with void pointer

尽管可以使用void指针(泛型指针)在C中编写通用代码,但我发现调试代码非常困难,因为void指针可以在没有编译器警告的情况下采用任何指针类型。 (例如,函数foo()接受void指针,它应该是指向struct的指针,但是如果传递char数组,编译器不会抱怨。)在C中使用void指针时,你们都使用什么样的方法/策略?

解决方案不是使用void*除非你真的,真的必须。 实际需要void指针的地方非常小:线程函数的参数,以及需要通过泛型函数传递特定于实现的数据的少数其他地方。 在每种情况下,接受void*参数的代码应该只接受通过void指针传递的一种数据类型,并且类型应该记录在注释中并且被所有调用者盲目地遵守。

这可能有所帮助:

comp.lang.c常见问题列表·问题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 **)和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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM