c - 在 POSIX 中将整数值转换为 void* 并再次返回是否总是安全的?

标签 c pthreads posix c99

这个问题几乎与我发现的其他一些问题重复,但这特别涉及 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 描述需要 intunsigned int至少为 32 位。这超出了 C99 要求它们至少为 16 位的要求。 (实际上,要求是根据范围,而不是大小,但效果是 intunsigned int 必须至少为 32(在 POSIX 下)或 16(在 C99 下)位,因为 C99 需要二进制表示。 )

<stdint.h> 的 POSIX 描述说intptr_tuintptr_t必须至少为 16 位,这与 C 标准强加的要求相同。自 void*可以转换为intptr_t并在不丢失信息的情况下再次返回,这意味着 void*可能小到 16 位。将其与 int 的 POSIX 要求相结合至少是 32 位(并且 POSIX 和 C 要求 long 至少是 32 位),并且 void* 可能是只是不够大,装不下 intlong不丢失信息的值(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/

相关文章:

比较 chars[] 不起作用

c - 通过串行端口读取值

c - 在 Windows 上使用 Mingw 的 pthread 时出错

c - 如何获取网络设备统计信息?

c++ - 奥尔森时区与Posix时区转换

c - 新声明后内存地址是否改变?

c++ - cUrl 命令 C++ 代码替换

c - gcc -march= native 。检测为错误架构构建的二进制文件的方法?

c++ - 终止阻塞的 pthreads 线程

c - C 中的宽字符输入/输出是否始终读取/写入正确的(系统默认)编码?