简体   繁体   中英

clarification on void *

since we can only cast a pointer to another pointer, how exactly "(void *) t and (int)threadid" are working in the below code? shouldnt we use &t instead of t?

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0;t<NUM_THREADS;t++){
     printf("In main: creating thread %ld\n", t);
     rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
     if (rc){
       printf("ERROR; return code from pthread_create() is %d\n", rc);
       exit(-1);
       }
     }

   /* Last thing that main() should do */
   pthread_exit(NULL);
}

To expand on my comment, C explicitly provides that pointers can be converted to integers and vise versa . Except for integer constants with value 0 (which convert reliably to NULL pointers), the result is implementation-defined. Such a conversion required to be reversible only as described in my addendum below.

In practice, however, it is common that pointer representations take a form equivalent to n -bit unsigned integers, for some n . On these, it is often the case that you safely can convert back and forth between pointers and integers of sufficient width without losing information. It is even more likely (but still not guaranteed) that you can round-trip from (not-too-wide) integer to pointer and back without losing information, even if perhaps you cannot safely do pointer -> integer -> pointer. Conforming C implementations will document the details of all implementation-defined behaviors, including these.

The program you presented depends on such conversions; they will work in many environments, but whether they in fact do depends on the C implementation in use. Such implementation dependence would be avoided by passing a bona fide pointer instead (and using it as one), as you suggested.

Updated to add:

In comments, @IanAbbott raised type intptr_t , which C2011 describes this way:

a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer [...] optional.

-- C2011, 7.20.1.4

A conforming implementation that provides this type will ensure that its behavior with respect to conversion is as specified, but because it is optional for implementations to provide it, this does not conflict with the implementation-specified nature of pointer/integer conversions (which is described in C2011 6.3.2.3/3-6). Even implementations that do provide this type do not thereby accept any obligation at all with respect to conversions involving other integer types (or other pointer types).

Note also that although intptr_t or uintptr_t , where available, provides for round-trip conversions from pointer to integer back to pointer, its provision has no bearing on integer to pointer back to integer, as far as the standard is concerned.

Here,

 rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);

the cast in the last argument a long ( t ) casts to a void * (which is the argument passed to the thread function). The cast is done because pthread_create() accepts a void * as the last argument.

The value is again converted back to long value from void * here:

   tid = (long)threadid;

But this conversion is entirely implementation-defined and is potentially allowed to be a trap representation (thus undefined ). So this conversion is not safe.

What you can instead is to use a temporary array:

  long arr[NUM_THREADS];

  for(t=0;t<NUM_THREADS;t++){
     printf("In main: creating thread %ld\n", t);
     arr[t] = t; 
     rc = pthread_create(&threads[t], NULL, PrintHello, &arr[t]);
     ...

But this involves making sure the array arr lifetime isn't over before the threads receive the value. This can be done using pthread_join() in main thread or using a malloc ed pointer (instead of using a local array arr ) or using an array with static storage duration such as making arr global.

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