像(void **)和device_array这样的转换有什么问题?

问题描述 投票:15回答:1

关于使用this answer的另一个问题有cudaMalloc((void**)&device_array, num_bytes),它使用void**作为输出参数,而不是传递void*作为返回值,如标准的malloc

它批评了NVIDIA的API并声明:

如(void **)和device_array中的转换是无效的C并导致未定义的行为。

并且已被多次投票(截至目前为8),所以我认为其中有一些道理。

我不明白在那里铸造有什么问题。

  • 什么是无效的C?
  • 在什么情况下会导致未定义的行为?

我所知道的是,它在没有警告的情况下进行编译,并按照预期的行为运行。但我对C达到标准规格水平并不了解。

c cuda
1个回答
9
投票

问题是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:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未针对引用的类型正确对齐,则行为未定义。

© www.soinside.com 2019 - 2024. All rights reserved.