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

Nya*_*yan 10 c generics pointers

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

JSB*_*ոգչ 9

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

  • OP特别提到了泛型编程,这是void*的一个非常好的用例(在没有更高级语言设施的情况下,比如模板或漂亮的宏.) (4认同)
  • @JS:是的,当你进行通用编程时,你需要做的地方数量比卡车更接近卡车;-) (2认同)

Rob*_*nes 5

这可能有帮助:

\n\n

comp.lang.c 常见问题列表 \xc2\xb7 问题 4.9

\n\n

问:假设我想编写一个将通用指针作为参数的函数,并且我想模拟通过引用传递它。我可以给形参类型void **,并做这样的事情吗?

\n\n
void f(void **);\ndouble *dp;\nf((void **)&dp);\n
Run Code Online (Sandbox Code Playgroud)\n\n

答: 不可携带。这样的代码可能有效并且有时被推荐,但它依赖于具有相同内部表示的所有指针类型(这是常见的,但不通用;参见问题 5.17)。

\n\n

C 中没有通用指针到指针类型。 void * 充当通用指针只是因为当其他指针类型分配给 void * \'s 或从 void * \'s 分配其他指针类型时,会自动应用转换(如果需要);如果尝试间接指向指向除 void * 之外的指针类型的 void ** 值,则无法执行这些转换。当您使用 void ** 指针值时(例如,当您使用 * 运算符访问 void ** 指向的 void * 值时),编译器无法知道该 void * 值是否曾经存在过从其他一些指针类型转换而来。它必须假设它只不过是一个 void *;它不能执行任何隐式转换。

\n\n

换句话说,您使用的任何 void ** 值都必须是某处实际 void * 值的地址;像 (void **)&dp 这样的强制转换虽然可能会关闭编译器,但它们是不可移植的(甚至可能无法执行您想要的操作;另请参阅问题 13.9)。如果 void ** 指向的指针不是 void *,并且它的大小或表示方式与 void * 不同,则编译器将无法正确访问它。

\n\n

为了使上面的代码片段工作,您必须使用中间 void * 变量:

\n\n
double *dp;\nvoid *vp = dp;\nf(&vp);\ndp = vp;\n
Run Code Online (Sandbox Code Playgroud)\n\n

如有必要,vp 之间的赋值使编译器有机会执行任何转换。

\n\n

同样,到目前为止的讨论假设不同的指针类型可能具有不同的大小或表示形式,这在今天很少见,但并非闻所未闻。为了更清楚地理解 void ** 的问题,请将这种情况与涉及 int 和 double 类型的类似情况进行比较,它们可能具有不同的大小,当然也有不同的表示形式。如果我们有一个函数

\n\n
void incme(double *p)\n{\n    *p += 1;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么我们可以做类似的事情

\n\n
int i = 1;\ndouble d = i;\nincme(&d);\ni = d;\n
Run Code Online (Sandbox Code Playgroud)\n\n

i 将增加 1。(这类似于涉及辅助 vp 的正确 void ** 代码。)另一方面,如果我们尝试类似的操作

\n\n
int i = 1;\nincme((double *)&i);    /* WRONG */\n
Run Code Online (Sandbox Code Playgroud)\n\n

(此代码类似于问题中的片段),它不太可能起作用。

\n