关于使用this answer的另一个问题有cudaMalloc((void**)&device_array, num_bytes)
,它使用void**
作为输出参数,而不是传递void*
作为返回值,如标准的malloc
。
它批评了NVIDIA的API并声明:
如(void **)和device_array中的转换是无效的C并导致未定义的行为。
并且已被多次投票(截至目前为8),所以我认为其中有一些道理。
我不明白在那里铸造有什么问题。
我所知道的是,它在没有警告的情况下进行编译,并按照预期的行为运行。但我对C达到标准规格水平并不了解。
问题是void*
在C中有特殊含义,有特殊规则(1)。它是唯一可以安全地转换任何其他指针类型的指针类型。但是,这些特殊规则不会递归地应用于void**
。
意思是像int* ptr = malloc(x);
这样的代码非常好,但是
int* ptr;
cudaMalloc(&ptr, x); // bad
不行!从int**
到void**
的指针转换没有明确定义。从理论上讲,这可能会导致不确定的行为和错位(2)。
此外,指针别名也可能存在问题。编译器可以自由地假设void**
的内容永远不会通过int**
访问,因此可能会以意想不到的方式优化代码,从而导致违反严格别名规则(6.5)的未定义行为。
这意味着您必须编写这样的代码才能安全地使用该函数:
void* vptr;
int* iptr;
cudaMalloc(&vptr, x);
iptr = vptr;
(1)C11 6.3.2.3/1:
指向void的指针可以转换为指向任何对象类型的指针。指向任何对象类型的指针可以转换为指向void的指针,然后再返回;结果应该等于原始指针。
(2)C11 6.3.2.3/7:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未针对引用的类型正确对齐,则行为未定义。