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

C - Threads Function: Casting a (void*) to a (long) and code works? But how?

下面函数printHello接收一个空指针作为参数。 但是这个指针被转换为 long 并且代码有效。我不认为我理解这种转换是如何工作的。指针类型不应该保存地址吗? 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!

with (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);

}

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

这种转换的结果是实现定义的,但在实践中往往效果很好。标准备注 "mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment".

除了一些不寻常的表示,如果两种类型具有相同的数据位数,则转换应该双向进行。该标准指定指针可以转换为 intptr_tuintptr_t 并再次转换回来,这在实践中通常意味着这些类型至少与指针一样大。许多旧代码使用 long 用于相同目的。似乎无法保证该程序所需的另一个方向的往返安全。虽然它通常有效。