C - 线程函数:将(void *)转换为(long)并且代码有效吗?但是怎么样?

时间:2017-10-26 09:16:36

标签: c pointers pthreads void-pointers

函数 printHello 以下 接收无效指针 作为参数。 但是这个指针会被转换成很长的代码并且代码可以运行。我不认为我理解这种转换是如何运作的。 Aren的指针类型应该保存地址吗? 如何将long类型突然兼容转换为指针类型,反之亦然?

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define NUM_OF_THREADS 5

void *printHello (void *thread_id)
{
    long tid;
    tid = (long) thread_id; // Why is this possible?
    printf("hello from thread #%ld!", tid);
    pthread_exit(NULL);
}

int main()
{
    pthread_t threads[NUM_OF_THREADS]; 
    int return_code;
    long i;

    for(i=0; i<NUM_OF_THREADS; i++)
    {
        printf("In main: creating thread %ld\n", i);

        return_code = pthread_create(&threads[i],NULL,printHello,(void*) i); 
        // Why does it allow to cast 'long i' into '(void*) i'?

        if(return_code) 
        {
            printf("Error: return code from pthread_create is %d\n", return_code);
            exit(-1);
        }
    }
    pthread_exit(NULL);
}

示例输出:

In main: creating thread 0
In main: creating thread 1
hello from thread #0!
hello from thread #1!
In main: creating thread 2
In main: creating thread 3
hello from thread #2!
In main: creating thread 4
hello from thread #3!
hello from thread #4!

2 个答案:

答案 0 :(得分:3)

整数可以转换为任何指针类型,任何指针类型都可以转换为整数类型,因为语言标准是这样说的。地址和整数都是固定长度的位集合,因此没有什么不可能的。

这种转换的结果是实现定义的,但它在实践中往往很有效。标准备注&#34;映射函数将指针转换为整数或整数转换为指针,旨在与执行环境的寻址结构保持一致&#34;。

除非有一些不寻常的表示,如果两种类型的数据位数相同,则转换应该双向工作。该标准指定指针可以转换为intptr_tuintptr_t并再次返回,这实际上通常意味着这些类型至少与指针一样大。许多旧代码使用long用于相同目的。似乎无法保证另一方向的往返安全,这是该计划所需要的。它通常有用。

答案 1 :(得分:1)

(void*) i您对编译器撒谎,使其认为i是一个地址。迫使演员总是做点什么。并不意味着它的推荐。

它有用(只要您不尝试取消引用该值),因为void *具有相同的大小或大于long,但它肯定是实现的定义,应该避免。

您应该将指针传递给您的数据(因为您的变量在main中声明且具有兼容的范围,所以它没有问题)

 return_code = pthread_create(&threads[i],NULL,printHello,&i); 

并在您的线程代码中取消引用它:

void *printHello (void *thread_id)
{
    long tid = *((long *)thread_id);

}