简体   繁体   中英

When is casting void pointer needed in C?

I've been looking at Advanced Linux Programming by Mitchell, Oldham and Samuel. I've seen in the section on pthreads something about void pointers and casting that confuses me.

Passing an argument to pthread_create(), they don't cast the pointer to a void pointer even though that is what the function expects.

pthread_create( &thread, NULL, &compute_prime, &which_prime );

Here, which_prime is of type int .

But taking a value returned from the thread using pthread_join, they DO cast the variable to void pointer.

pthread_join( thread, (void*) &prime );

Here, prime is of type int again.

Why is casting done in the second instance and not in the first?

The second example is a good example of why casting to void* is usually a mistake. It should be

void *primep = ′  // no cast needed
pthread_join(thread, &primep);

because pthread_join takes a void** as its second argument. The void* only makes sure the bug passes the compiler because the void* is converted to void** automatically.

So, when do you need to cast to void* or back:

  • when working with pointers stored as integers ( (u)intptr_t );
  • when passing pointers to functions that have an incomplete prototype and take void* (or take a different type of pointer and you have void* ); that usually means functions taking a variable number of arguments such as printf .

No need to cast from or to a pointer to void in C:

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.


The only exceptions from this are

  • when printing a pointer using the "%p" conversion specifier as it's only defined for void * .
  • when copying a pointer's value from an intptr_t or uintptr_t back to a void * .

In C, casting to void* from any pointer type and vice-versa is done implicitly. There's no need for the cast in the second example.

(Note that in C++ casting any pointer to void* is also done implicitly (except for function pointers and function-member / method pointers which cannot be cast to void*), but casting back requires an explicit cast.)

As per the documentation,

int pthread_join(pthread_t thread, void **retval);

So, the pthread_join takes a pointer to void* as its second argument. This is because,

In pthread_join, you get back the address passed to pthread_exit by the finished thread. If you pass just a plain pointer, it is passed by value so you can't change where it is pointing to. To be able to change the value of the pointer passed to pthread_join, it must be passed as a pointer itself, that is, a pointer to a pointer.

Now, to your question, " Why is casting done in the second instance and not in the first? " In the first instance, ie, pthread_create , it expects a void* as its fourth argument. So passing &which_prime would be implicitly converted to void* .

In the second instance, ie, pthread_join , it expects a void** and we are passing &prime there. So, the compiler will complain. So, to bypass the bug, the author passes a cast of void* which will be automatically converted to void** .

But this is not a good solution.

The Solution::

void* prime ; // make prime as void*
pthread_join( thread, &prime );
printf( "%" PRIxPTR "\n", (intptr_t)prime ) ; 
// intptr_t instead of int to get an integer type 
// that's the same size as a pointer

I believe the same code has been referenced in other questions .

The answer in the second link explains:

It's not valid. It simply happens to work if sizeof(int) == sizeof(void *), which happens on many systems.

A void * is only guaranteed to be able to hold pointers to data objects.

Here is a C FAQ on the subject.

And the quoted text:

How are integers converted to and from pointers? Can I temporarily stuff an integer into a pointer, or vice versa?

Pointer-to-integer and integer-to-pointer conversions are implementation-defined (see question 11.33), and there is no longer any guarantee that pointers can be converted to integers and back, without change

Forcing pointers into integers, or integers into pointers, has never been good practice

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM