我观察到使用一些预定义的函数,我应该将数据转换为void*
,然后将其传递给函数。这很容易理解。
我的问题是这两个演员之间的区别是什么:
(void **)&a
(void*)a
我应该使用哪一种,有什么区别?
答案 0 :(得分:1)
你写道,“这很容易理解”。显然不是。首先,您没有投射数据,数据没有发生任何变化。其次,使用a
vs &a
传递给函数的内容完全不同。 void指针只是对某些数据的引用。底层数据类型未知(对编译器)。由于这个原因,您无法执行指针运算,例如。
假设你使用malloc()一块内存来存储一些数据,返回的指针是值0x2020并分配给x。现在假设x位于存储器位置0x1000处的堆栈区域。这意味着x是0x2020。 * x是您放入malloc'd区域的数据。现在重要的部分..& x是0x1000,这是x的内存地址,在我们假设的情况下,这是在堆栈上。以下示例演示了一点void *
和void **
。这只是一个快速的样本,而不是除了演示概念之外做任何事情的正确方法。
#include <stdio.h>
struct t1 { int a; };
struct t2 { int b; };
int testvppa(void **pp){
void *p = *pp;
struct t1 * pt = (struct t1 *)p; // need to cast in order to de-reference
return pt->a;
}
int testvppb(void **pp){
void *p = *pp;
struct t2 * pt = (struct t2 *)p; // need to cast in order to de-reference
return pt->b;
}
int testvp(void *p, int which){
if (which == 1)
{
return testvppa(&p);
}
else{
return testvppb(&p);
}
}
int main(){
struct t1 stuffa = { 123 };
struct t2 stuffb = { 456 };
void * vp;
printf("stuffa: {%d} @ %p\n", stuffa.a, &stuffa);
printf("stuffb: {%d} @ %p\n", stuffb.b, &stuffb);
vp = &stuffa;
printf("vp: %p test: %d\n", vp, testvp(vp,1));
vp = &stuffb;
printf("vp: %p test: %d\n", vp, testvp(vp,2));
return 0;
}
在我的机器上运行会产生以下结果:(注意指针的地址会改变,但值123和456将是相同的。)
stuffa: {123} @ 0x7fff28116db0
stuffb: {456} @ 0x7fff28116dc0
vp: 0x7fff28116db0 test: 123
vp: 0x7fff28116dc0 test: 456
我的答案很可能比启发更令人困惑。这就是为什么对你的问题的实际正确答案正是Oli Charlesworth在评论中所说的:“我建议先学习C,然后发表问题”
答案 1 :(得分:0)
第一个将地址传递给指向函数的指针(指针指针)。通过取消引用它,该函数应该能够返回指向您的指针作为输出参数。
第二个只能用作输入参数。
示例(在C代码中):
struct stuff { int t; };
void allocate_stuff(void **allocated) {
struct stuff *opaque = malloc(sizeof(*opaque));
*allocated = opaque; /* the dereferencing I mentioned - sets "output" value */
}
void deallocate_stuff(void *allocated) {
free(allocated);
}
void * handle = NULL;
allocate_stuff(&handle); /* can return pointer due to */
deallocate_stuff(opaque);
编辑:要理解为什么第一个是“输出参数”,你可以查看正式/实际的参数定义。