There is this answer on another question about the use of cudaMalloc((void**)&device_array, num_bytes)
, which uses void**
as output argument instead of passing a void*
as return value like the standard malloc
.
It criticizes NVIDIA's API and states :
Casting, as in (void**)&device_array, is invalid C and results in undefined behavior.
and has been upvoted several times (8 as of now), so I assume there is some truth in it.
I don't understand what's wrong with casting there.
All I know is that it compiles without warning and runs with the intended behavior for me. But I am not knowledgeable with C up to standard specification level.
Casting to void is used to suppress compiler warnings. The Standard says in §5.2. 9/4 says, Any expression can be explicitly converted to type “cv void.” The expression value is discarded. Follow this answer to receive notifications.
A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address. A void pointer can be a null pointer.
Any pointer to an object, optionally type-qualified, can be converted to void* , keeping the same const or volatile qualifications.
Why we use void pointers? We use void pointers because of its reusability. Void pointers can store the object of any type, and we can retrieve the object of any type by using the indirection operator with proper typecasting.
The problem is that void*
has a special meaning in C, with special rules (1). It is the only pointer type to/from which you can safely convert any other pointer type. However, these special rules do not apply recursively to void**
.
Meaning that code like int* ptr = malloc(x);
is perfectly fine, but
int* ptr;
cudaMalloc(&ptr, x); // bad
is not fine! A pointer conversion from int**
to void**
is not well-defined. In theory this could cause undefined behavior and misalignment (2).
In addition, there might also be problems with pointer aliasing. The compiler is free to assume that the contents of a void*
is never accessed through a int**
and could therefore optimize the code in unexpected ways, leading to undefined behavior for violation of the strict aliasing rule (6.5).
Which means you will have to write code like this in order to safely use the function:
void* vptr;
int* iptr;
cudaMalloc(&vptr, x);
iptr = vptr;
(1) C11 6.3.2.3/1:
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
(2) C11 6.3.2.3/7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With