Reputation: 79
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
Upvotes: 1
Views: 77
Reputation: 17438
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);
Upvotes: 1