这个问题几乎与我发现的其他一些问题重复,但这特别涉及 POSIX,并且是我多次遇到的 pthreads 中一个非常常见的示例。我主要关心当前的事态(即 C99 和 POSIX.1-2008 或更高版本),但任何有趣的历史信息当然也很有趣。
问题基本上可以归结为 b 是否总是与以下代码中的 a 取相同的值:
long int a = /* some valid value */
void *ptr = (void *)a;
long int b = (long int)ptr;
我知道这通常有效,但问题是这样做是否正确(即,C99 和/或 POSIX 标准是否保证它会有效)。
说到 C99 似乎没有,我们有 6.3.2.3:
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.56)
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.
即使使用 intptr_t,该标准似乎也只能保证任何有效的 void* 可以转换为 intptr_t 并再次转换回来,但它不保证任何 intptr_t 可以转换为 void* 并再次转换回来。
然而,POSIX 标准仍然有可能允许这样做。
我不太希望使用 void* 作为任何变量的存储空间(我发现它非常难看,即使 POSIX 允许它),但我觉得我不得不问,因为 pthreads_create 的常见示例使用函数,其中 start_routine 的参数是一个整数,它作为 void* 传入,并在 start_routine 函数中转换为 int 或 long int。例如this manpage有这样一个例子(完整代码见链接):
//Last argument casts int to void *
pthread_create(&tid[i], NULL, sleeping, (void *)SLEEP_TIME);
/* ... */
void * sleeping(void *arg){
//Casting void * back to int
int sleep_time = (int)arg;
/* ... */
}
我在教科书(Peter S. Pacheco 的并行编程简介)中也看到过类似的例子。考虑到这似乎是应该比我更了解这些东西的人使用的一个常见示例,我想知道我是否错了,这实际上是一件安全且便携的事情。
最佳答案
如您所说,C99 不保证任何整数类型都可以转换为 void*
并在不丢失信息的情况下返回。它确实为 intptr_t
做出了类似的保证和 uintptr_t
在 <stdint.h>
中定义,但这些类型是可选的。 (保证 void*
可以转换为 {u,}intptr_t
并返回而不会丢失信息;对于任意整数值没有这样的保证。)
POSIX 似乎也没有做出任何此类保证。
<limits.h>
的 POSIX 描述需要 int
和 unsigned int
至少为 32 位。这超出了 C99 要求它们至少为 16 位的要求。 (实际上,要求是根据范围,而不是大小,但效果是 int
和 unsigned int
必须至少为 32(在 POSIX 下)或 16(在 C99 下)位,因为 C99 需要二进制表示。 )
<stdint.h>
的 POSIX 描述说intptr_t
和 uintptr_t
必须至少为 16 位,这与 C 标准强加的要求相同。自 void*
可以转换为intptr_t
并在不丢失信息的情况下再次返回,这意味着 void*
可能小到 16 位。将其与 int
的 POSIX 要求相结合至少是 32 位(并且 POSIX 和 C 要求 long
至少是 32 位),并且 void*
可能是只是不够大,装不下 int
或 long
不丢失信息的值(value)。
pthread_create()
的 POSIX 描述这并不矛盾。它只是说 arg
(void*
pthread_create()
的第 4 个参数)传递给 start_routine()
.大概意图是 arg
指向一些数据 start_routine()
可以使用。 POSIX 没有显示 arg
用法的示例.
可以看到POSIX标准here ;您必须创建一个免费帐户才能访问它。
关于c - 在 POSIX 中将整数值转换为 void* 并再次返回是否总是安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7822904/