像(void **)和device_array这样的转换有什么问题?
关于使用cudaMalloc((void**)&device_array, num_bytes)
另一个问题有这个答案 ,它使用void**
作为输出参数,而不是像标准malloc
那样传递void*
作为返回值。
它批评了NVIDIA的API并声明:
如(void **)和device_array中的转换是无效的C并导致未定义的行为。
并且已被多次投票(截至目前为8),因此我认为其中有一些道理。
我不明白在那里投掷有什么问题。
- 什么是无效的C?
- 在什么情况下会导致未定义的行为?
我所知道的是,它在没有警告的情况下进行编译,并以我的预期行为运行。 但是我不了解C达到标准规格水平。
问题是void*
在C中具有特殊含义,具有特殊规则(1)。 它是唯一可以安全地转换任何其他指针类型的指针类型。 但是,这些特殊规则不会递归地应用于void**
。
意思是像int* ptr = malloc(x);
这样的代码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:
指向对象类型的指针可以转换为指向不同对象类型的指针。 如果生成的指针未针对引用的类型正确对齐,则行为未定义。