将int转换为void *或反之亦然意味着什么?

从存储器的角度来看,将整数值转换为void*或反之亦然? 我的理解是void*是一个未指定长度的内存块的地址。
这似乎就像比较苹果和橘子一样。

 int myval = 5; void* ptr = (void*)myval; printf("%d",(int)ptr); 

我意识到我应该给出使用它的确切上下文。

 int main(int argc, char* argv[]) { long thread; /* Use long in case of a 64-bit system */ pthread_t* thread_handles; /* Get number of threads from command line */ if (argc != 2) Usage(argv[0]); thread_count = strtol(argv[1], NULL, 10); if (thread_count  MAX_THREADS) Usage(argv[0]); thread_handles = malloc (thread_count*sizeof(pthread_t)); for (thread = 0; thread < thread_count; thread++) pthread_create(&thread_handles[thread], NULL, Hello, (void*) thread); printf("Hello from the main thread\n"); for (thread = 0; thread < thread_count; thread++) pthread_join(thread_handles[thread], NULL); free(thread_handles); return 0; } /* main */ /*-------------------------------------------------------------------*/ void *Hello(void* rank) { long my_rank = (long) rank; /* Use long in case of 64-bit system */ printf("Hello from thread %ld of %d\n", my_rank, thread_count); return NULL; } /* Hello */ 

这段代码来自Peter Pachecho关于并行编程的书。

intvoid *是没有意义的,不应该像你试图将非指针强制转换为指针一样。 引用C99标准 ,第6.3.2.3节第5项:

整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

可以int *void * (任何指针都可以转换为void * ,您可以将其void *所有指针的“基本类型”)。

void *int是不可移植的,并且可能完全错误,具体取决于您使用的平台(例如, void *可能是64位宽, int可能只是32位)。 再次引用C99标准,第6.3.2.3节第6项:

任何指针类型都可以转换为整数类型。 除了之前指定的以外,结果是实现定义的。 如果结果无法以整数类型表示,则行为未定义。 结果不必在任何整数类型的值范围内。

为了解决这个问题,一些平台提供了uintptr_t ,它允许您将指针视为适当宽度的数值。

void*指针(或任何指针)和int粗略地说都是数字。 它们可能具有不同的bitsize,但指针不可能小于int ,因此操作可以反转。 当然,这是非法的,你永远不应该取消引用没有有效位置指针的指针。

C标准指定必须可以将void指针转换为整数类型,以便将整数类型转换回void指针将产生相同的指针。 我不确定它是否需要将空指针转换为整数会产生零值,或者只有数字文字零被识别为特殊值。 在许多实现中,整数值表示硬件地址,但标准没有这样的保证。 完全有可能在包含硬件地址0x12345678的特殊陷阱的硬件上,将指针转换为整数将从硬件地址中减去0x12345678,并且将整数转换为指针会将0x12345678添加回(因此整数值为零表示空指针)。

在许多情况下,特别是在开发嵌入式控制器时,编译器供应商将明确指定在将特定整数值转换为指针类型时将访问的硬件地址。 在具有单个线性地址空间的处理器上,将整数值0x12345678转换为指针通常会产生一个指向地址0x12345678的指针。 硬件参考手册将指出该位置是否有任何特殊之处。 在具有更多“有趣”地址空间的处理器上,可能需要使用除硬件地址之外的其他内容作为指针。 例如,在古董IBM PC计算机上,显示缓冲区映射到硬件地址0xB8000,但在大多数编译器中,地址将表示为(short far *)0xB8000000。

这很像比较苹果和橘子。 此代码工作的唯一方法是因为您明确地来回转换它。

C编译器只是将int中的字节复制到指针和返回的空间,就像在int中保存char一样。

如果由于某种原因’int’比平台上的’void *’长,这甚至可能导致你的号码混乱。

如果你确实想要一个从整数转换为指针和返回的数字,请查看intptr_t 。 该类型实际上旨在存储整数和指针。

能够将指针转换为指针算术的整数类型是很有用的。 例如, offsetof()宏计算结构中成员的偏移量,需要这种转换。

但是,必须确保用于此的基本类型能够处理指针:例如,对于64 Linux,当使用gcc时,情况并非如此: void *大小为8,int的大小为4。

offsetof宏定义如下:

 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 

它在Linux内核的双链表实现中占有突出地位,非常简单地定义为:

 struct list_head { struct list_head *prev, *next; } 

此结构嵌入在内核结构中,如:

 struct something { //... struct list_head list; //... } 

在遍历列表时,代码需要获取指向编码结构的指针。 这样做(简化定义):

 #define container_of(ptr, type, member) \ (type *)((char *)ptr - offsetoff(type, member)) #define list_entry(list, type, member) \ container_of(list, type, member) 

在代码中,您经常会看到:

 struct something *s; list_for_each(listptr, somehead) { s = list_entry(listptr, struct something, list); //... } 

如果没有这种宏和指针算法,这将是不可行的。 但它非常依赖于工具链。

如果正在进行任何比较,那就像将苹果与橙子进行比较一样。 但事实并非如此。 基本上,在大多数体系结构中,int可以被转换为void指针而不会丢失任何信息,并且void指针也可以被转换回int,同样不会丢失任何信息。 当然,您不应该尝试取消引用该指针,因为它不指向任何有意义的内存位置:它只是一个变量,包含与整数在转换之前包含的位模式相同的位模式。