(void **)&x 和 (void *)x 有什么区别?

3
(void **)&x 和 (void *)x 有什么区别?下面是一些代码,请帮忙解决。
(注意:本文中的 & 是 HTML 中 & 符号的转义字符,实际使用时应该将 & 替换为 & 符号)
float *xd;
int size=width*width*size(float);
cudaMalloc((void **)&x,size); 1
cudaMalloc((void *)x,size);   2
cudaMalloc(&x,size);          3
cudaMalloc(*x,size);          4

cudaFree(xd);

我只想知道它们之间的区别。
cudaMalloc()函数的第一个参数是指向分配对象后必须指向的指针变量的地址。指针变量的地址应转换为(void **),因为该函数期望通用指针值;内存分配函数是通用函数,不限于任何特定类型的对象。此地址允许cudaMalloc()函数将所分配对象的地址写入指针变量中。cudaMalloc()函数的第二个参数以字节为单位给出要分配的对象的大小。使用这第二个参数与C中malloc()函数的size参数一致。

C++decl 可能在这里有用。 - Eric
3
这与 &x 和 x 之间的区别几乎相同。如果不知道为什么认为两个非常不同的事物是相同的,这样的问题就没有用处。 - Jim Balter
2个回答

6

它们几乎是完全不同的。

这个:

(void **)&x

x的地址转换为void**(指向void的指针)。

这样写:

(void *)x

x转换为void*指针。它们都是指针,但它们指向内存中完全不同的位置(除非x恰好包含自己的地址),并且它们是不同类型的。如果您想展示代码,展示编译实际源代码将会很有帮助。复制并粘贴您的实际源代码;不要重新输入。您还没有展示x的声明(xd是否错别字?),而size(float)是语法错误(您是否想表达sizeof(float)?)。

3
为了更好地理解为什么在使用cudaMalloc时通常需要写(void**)&var,考虑以下内容:
cudaMalloc在GPU上分配内存。引用的内存类型是void*,因为它实际上不关心数据类型。
一旦我们有了刚刚分配的cudaMalloc内存的地址,我们需要将其返回给调用者。但是,所有CUDA API函数都会返回错误代码(或成功代码),任何其他返回的数据都必须通过参数引用传递回去。
C语言没有按引用传递的方式,因此您实际上需要传递一个指向变量的指针,以便函数将结果存储在该变量中。由于您想存储指针值,因此需要传递指向指针的指针,因此是void**类型。
如果想以类似的方式封装malloc,则可以编写以下内容:
void myMalloc(void** ret, size_t size) {
    void* mem = malloc(size);
    *ret = mem;
}

现在,如果你将 (void**)&var 传递给 myMalloc,函数将能够覆盖 var 的值,因为 ret 将指向 var 变量。
这样说清楚了吗?

但这是未定义行为;你需要使用一个 void* 临时变量 - Davis Herring
@DavisHerring 您指的是什么? - CygnusX1
抱歉表述不清:通过(void**)&var产生的指针存储是未定义行为(除非var实际上是void*类型的平凡情况)。使用cudaMalloc的方法是float *f; {void *v; if(cudaMalloc(&v,n*sizeof*f)) …; f=v;} - Davis Herring
对于大多数架构和编译器,您可以在void **T **之间进行转换(其中T不是函数)。对于C标准而言,这并不适用,因为CUDA根据定义超出了标准的范围,因此是一个未定义的行为。 - CygnusX1
你可以进行类型转换,但优化器允许假设结果没有存储发生(除非首先将其转换回正确的类型)。这个问题实际上并不是关于CUDA的,只是举个例子,即使C/CUDA实现为了实用性而做出了妥协(这并不是UB,因为它是一个扩展),也没有理由鼓励错误的习惯。 - Davis Herring

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接