简体   繁体   中英

How can this code be of type pointer to pointer to void?

I am studying c language now. While studying, I saw the code, but there is one part I don't understand.

int main(int argc, char* argv[]){
    pthread_t  t_id;
    int arg = 10;
    int result;
    int *p;

    result = pthread_create(&t_id, NULL, thread_main, (void *)&arg);
    if(result != 0){
        errno = result;
        perror("create");
    }
    pthread_join(t_id, (void *)&p);
    printf("%d\n", *p);
    return 0;
}
pthread_join(t_id, (void *)&p);

If it is forced casting, I think it should be (void*)type but I am wondering how the variable p turns from (void*)&p to a void**p type.

Shouldn't it be written in (void**)&p

These lines of code are incorrect:

   int *p;
   /* ... */
    pthread_join(t_id, (void *)&p);
    printf("%d\n", *p);

pthread_join 's second parameter is void **retval and if non-null, will copy the exit value of the thread to *retval . The exit value and the type of *retval are both of type void* as far as pthread_join is concerned, but the underlying object p in the caller is of type int* . This results in undefined behavior because the effective type of p is its declared type int * but its stored value is being accessed by an lvalue expression ( *retval ) that does not satisfy the requirements of C11 6.5/7 :

An object shall have its stored value accessed only by an lvalue expression that has one of the following types: 88)

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type.

88) The intent of this list is to specify those circumstances in which an object may or may not be aliased.

The cast operation (void *)&p serves to hide the problem. Any value of an object pointer type can be converted to void * and back to the original pointer type and will compare equal to the original pointer value. But in this case, the pointer value is being converted back to a different, incompatible pointer type.

The printf("%d\n", *p); is not incorrect itself, but the storage location *p was accessed incorrectly by the call to pthread_join , so the value of p and therefore the value of *p may be invalid.

Assuming the thread's exit value is actually a void * pointing to an int object, the code can be written as follows to avoid the undefined behavior:

   void *pv;
   int *p;
   /* ... */
   pthread_join(t_id, &pv);
   p = pv;
   printf("%d\n", *p);

Or, omitting the extra variable:

   void *pv;
   /* ... */
   pthread_join(t_id, &pv);
   printf("%d\n", *(int *)pv);

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