2

Is it possible to directly type-caste a void pointer to long without causing a trouble? Below is a little code snippet I extracted from the code here (Example under Pthread Joining section of the page).

{
    void *status;
    long t;
    rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);
    rc = pthread_join(thread[t], &status);
    printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
}

As this manual page says that pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit()) into the location pointed to by *retval(*status in this case). But in the program I mentioned in question, status doesn't point to any location. Then how is it that the program still works?

And secondly,as far as my knowledge is concerned, status cannot hold a long value then how does typecasting status gives us a value which is long and not an address?

7_R3X
  • 3,904
  • 4
  • 25
  • 43
  • 1
    Duplicate of http://stackoverflow.com/questions/12949383/converting-primitive-data-type-to-void-pointer-type ? – Martin R Apr 10 '16 at 08:35
  • @MartinR : As [this](http://man7.org/linux/man-pages/man3/pthread_join.3.html) says that **pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit(3)) into the location pointed to by *retval**. But in the program I mentioned in question, _status_ doesn't point to any location then How does that program work? – 7_R3X Apr 10 '16 at 08:57
  • It works by chance. The variable status is not initialized so it will write to whereever status points to. By chance, it may be somewhere legal. If it is somewhere illegal, you will get a crash. – cup Apr 10 '16 at 09:26
  • @cup : Does that mean that the turorial is unreliable? And how did they get the correct output by type-casting the pointer to long instead of dereferencing it? – 7_R3X Apr 10 '16 at 09:36
  • Sorry - my previous comment was incorrect since you did not post the code that called pthread_exit. In the tutorial, pthread_exit casts a long to a void*. pthread_join gets the result of pthread_exit so it has to recast it back to long. The tutorial is reliable but it assumes that a void* takes up at least the same amount or more space than a long. – cup Apr 10 '16 at 10:50

2 Answers2

3

Quick answer: No, use intptr_t

Long answer: long is not guaranteed to fit into a void *. On some systems (notably 64-bit Intel Linux machines) it will work since void * and long are both 64-bit quantities and the Intel processor has no other type differences. On other machines such as 32-bit Intel Linux it will not work since long is 64-bit and void * 32-bit on those machines. More exotic machines have different properties.

The standard type that supports int <-> pointer conversions is intptr_t, found in stdint.h. According to the POSIX Programmer's Manual:

The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to a pointer to void, and the result will compare equal to the original pointer: intptr_t

So intptr_t is a signed integer type of unspecified length which is guaranteed to support conversions from and to void *. There is also unsigned uintptr_t.

Here is the definition of intptr_t in glibc. As you can see, on 64-bit machines intptr_t and long are indeed the same type.

jforberg
  • 6,537
  • 3
  • 29
  • 47
  • That documentation says `intptr_t` can hold the value of any pointer, not vice-versa. For example, if pointers are 32-bit and `intptr_t` is 64-bit, it would meet the requirements. (That is, the cast from pointer to integer and back would work.) I do not think there is any type guaranteed to have the opposite property. – Nemo Apr 10 '16 at 11:05
  • This is a good point, although reading the glibc source I feel confident it would in fact work with that particular implementation. But I agree that it's not required by the standard. Feel free to edit my answer to clarify. – jforberg Apr 10 '16 at 11:09
0

this line:

rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);

is not correct.

Suggest using:

rc = pthread_create(&thread[t], &attr, BusyWork, (void *)&t);

Then the 'problem' disappears

Note: in the Busywork() function get the actual value back by:

long myVar = *parmVoidPtr;
user3629249
  • 16,402
  • 1
  • 16
  • 17