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

发布于 2024-12-22 16:30:02 字数 1259 浏览 2 评论 0原文

从内存的角度来看,将整数值转换为 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 <= 0 || 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 的《并行编程》一书。

What does it mean to convert an integer value to a void* or viceversa from a memory point of view?
My understanding is void* is an address to a block of memory of unspecified length.
This seems to be something like comparing apple with oranges.

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

I realized that I should have given the exact context where this is used.

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 <= 0 || 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 */

This code is from Peter Pachecho's book on Parallel programming.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

爱人如己 2024-12-29 16:30:02

int 转换为 void * 是毫无意义的,不应该这样做,因为您会尝试将非指针转换为指针。引用 C99 标准,第 6.3.2.3 节第 5 项:

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

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

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

任何指针类型都可以转换为整数类型。除非作为
先前指定,结果是实现定义的。如果
结果不能用整数类型表示,行为是
不明确的。结果不必在任何值的范围内
整数类型。

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

Casting int to void * is rather meaningless and should not be done as you would be attempting to cast a non-pointer to a pointer. Quoting the C99 standard, section 6.3.2.3 item 5:

An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.

You could cast int * to void * (any pointer is convertible to void * which you can think of like the "base type" of all pointers).

Casting void * to int is not portable and may be completely wrong depending on the platform you use (e.g. void * maybe 64 bits wide and int may only be 32 bits). Quoting the C99 standard again, section 6.3.2.3 item 6:

Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.

To solve this, some platforms provide uintptr_t which allows you to treat a pointer as a numeric value of the proper width.

南巷近海 2024-12-29 16:30:02

粗略地说,void* 指针(或任何与此相关的指针)和 int 都是数字。它们可能具有不同的位大小,但指针不太可能小于int,因此使得操作可逆。当然,这是非法的,并且您永远不应该取消引用没有有效指向位置的指针。

Both void* pointer (or any pointer for that matter) and int are, roughly speaking, numbers. They may be of different bitsize, but it is unlikely that pointer is smaller than int, so that makes the operation reversible. Of course, it's illegal and you should never dereference the pointer that has no valid location to point to.

玩世 2024-12-29 16:30:02

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

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

The C standard specifies that it must be possible to convert a void pointer to an integral type such that converting the integral type back to a void pointer will yield the same pointer. I'm not sure if it requires that converting a null pointer to an integer yield the value zero, or if only numeric literal zeroes are recognized as special. On many implementations, the integer value represents a hardware address, but the standard makes no such guarantee. It would be entirely possible that on hardware which included a special trap for hardware address 0x12345678, converting a pointer to an integer would subtract 0x12345678 from the hardware address, and converting an integer to a pointer would add 0x12345678 back in (thus an integer value of zero would represent a null pointer).

In many cases, particularly when developing for embedded controllers, the compiler vendor will explicitly specify what hardware address will be accessed when converting a particular integer value to a pointer type. On processors with a single linear address space, converting an integer value 0x12345678 to a pointer would generally yield a pointer which refers to address 0x12345678; the hardware reference manual would indicate if there was anything special about that location. On processors with more 'interesting' address spaces, it may be necessary to use something other than the hardware address as the pointer. For example, on antique IBM PC computers, the display buffer was mapped at hardware address 0xB8000, but in most compilers, the address would be expressed as (short far*)0xB8000000.

忆梦 2024-12-29 16:30:02

这很像比较苹果和橘子。该代码起作用的唯一方法是因为您显式地来回转换它。

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

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

如果您确实希望将数字从整数转换为指针并返回,请查看intptr_t。该类型实际上旨在存储整数和指针。

This is quite like comparing apples and oranges. The only way that this code works is because you are explicitly casting it back and forth.

The C compiler is just copying the bytes from the int into the space for the pointer and back, just like how you can hold a char in an int.

This could even cause your number to be messed up if for some reason an 'int' is longer than a 'void *' on your platform.

If you actually do want have a number to convert from integers into pointers and back, look into intptr_t. That type is actually designed to store both integers and pointers.

虫児飞 2024-12-29 16:30:02

能够将指针强制转换为整数类型以进行指针算术非常有用。例如,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;
    //...
}

走路时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);
   //...
}

如果没有这种宏和指针算术,这根本不可能实现。但它非常依赖于工具链。

It is useful to be able to cast a pointer to integer type for pointer arithmetic. For instance, the offsetof() macro, which calculates the offset of a member within a structure, needs this kind of conversion.

However, it must be ensured that the primitive type used for this is able to handle a pointer: here, for 64 Linux for instance, when using gcc, this is not the case: void * has size 8, an int has size 4.

The offsetof macro is defined as such:

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

It is used prominently in the Linux kernel's doubly linked list implementation, very simply defined as:

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

This struct is embedded within kernel structures, as in:

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

When walking a list, the code needs to grab a pointer to the encoding structure. This is done as this (simplified definition):

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

And in the code, you will very often see:

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

which would simply not be doable without this kind of macro and pointer arithmetic. But it is very dependent on the toolchain.

悲欢浪云 2024-12-29 16:30:02

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

It would be like comparing apples with oranges if any attempt was being made to make any comparison. But there isn't. Basically, in the majority of architectures out there, an int can be casted to a void pointer without the loss of any information, and a void pointer can also be casted back to an int, again without the loss of any information. Of course, you should not try dereferencing that pointer, because it does not point to any meaningful memory location: it is just a variable containing the same bit-pattern as the bit pattern that the integer used to contain before the cast.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文