使用 intptr_t 代替 void*?

Posted

技术标签:

【中文标题】使用 intptr_t 代替 void*?【英文标题】:Using intptr_t instead of void*? 【发布时间】:2012-03-18 13:34:38 【问题描述】:

使用intptr_t 作为通用存储(保存指针和整数值)而不是void* 是个好主意吗? (如此处所示:http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html

对于我已经阅读的内容:

int -> void* -> int 往返不保证保持原值;我猜int -> intptr_t -> int 会做 void*intptr_t 上的指针算术都需要强制转换,所以这里没有任何优势 void* 表示在存储指针时较少显式转换,intptr_t 表示在存储整数值时较少转换 intptr_t 需要 C99

我还应该考虑什么?

【问题讨论】:

没有。 (如果是,那么他们只会将 intptr_t 的语义添加到 void* 帖子要求“(保存指针和整数值)”,但随后只讨论了intvoid *intptr_t。由于uintmax_tsize_tlong long等也是整数类型,听起来问题只是关于对象指针、intptr_tint类型。 【参考方案1】:

使用intptr_t 作为通用存储(保存指针和整数值)而不是void* 是个好主意吗?

没有。

intptr_t 不保证存在。首先,正如您所注意到的,它是在 C99 中引入的。其次,实现不需要具有足够大的整数类型来保存转换后的指针值而不会丢失信息。

int 转换为intptr_t 并返回不太可能丢失信息,但不能保证intptr_tint 更宽。

如果要存储指针值,请将它们存储在指针对象中。这就是指针对象的用途。

任何指向对象或不完整类型的指针都可以转换为void* 并再次返回而不会丢失信息。对于指向函数的指针没有这样的保证——但是任何指向函数的类型都可以转换为任何其他指向函数的类型并返回而不会丢失信息。 (我指的是 C 标准;我认为 POSIX 提供了一些额外的保证。)

如果您想在同一个对象中存储整数或指针值,您应该做的第一件事是重新考虑您的设计。如果您已经这样做了,并得出结论认为您确实想要这样做,请考虑使用联合(并仔细跟踪您最近存储的值类型)。

有些 API 使用 void* 参数来允许传递任意数据;例如,参见 POSIX pthread_create() 函数。这可以通过将整数值转换为 void* 来滥用,但传递整数对象的 地址 会更安全。

【讨论】:

请扩展“不太可能会丢失信息”。 intptr_t 确实往返一个指向比较 equally 的指针 - 可能不是相同的位模式导致您的评论信息丢失。 @chux:正如我所说,不能保证intptr_tint 更宽(尽管我知道没有实现)。例如,如果 intptr_t 是 32 位,int 是 64 位,则将 int 转换为 intptr_t 再转换回 int 可能会丢失信息。具体来说,如果int 值超出intptr_t 的范围,则第一次转换会产生实现定义的结果。 抱歉,将答案错误地解读为“将 指针 转换为 intptr_t 并返回不太可能丢失信息...”。我的评论就是基于这个想法。同意int/intptr_t 问题的罕见性。【参考方案2】:

不,您不能保证任何特定类型都是存储指针和整数的合理方式,此外,它会使您的代码混乱。有更好的办法。

如果要将整数和指针存储在同一个对象中,干净且可移植的方法是使用联合:

union foo 
   int integer_foo;
   void *pointer_foo;
;

这是便携式的,允许您以两者中较大者所需的存储大小存储这两种东西。保证始终有效。

【讨论】:

intvoid* 在布局方面是否有共同的初始子序列?否则,这是可移植的,您不允许同时存储两个成员,这绝对保证“始终有效”。 @LightnessRacesinOrbit 我不认为他声称可以同时将两个值存储在其中。 “both”表示其中可以存储int,也可以存储void *,但没有同时性的暗示。注意。 intvoid* 是否具有共同的初始序列并不重要,因为该规则仅适用于结构。 @M.M:我认为“两者”确实暗示了同时性,而“任何一个”都不会这样做,但谁知道呢。当然,鉴于问题中谈到了往返转换,OP 正在寻找同时性,所以如果这个答案没有错,那么它至少会发布在错误的问题上:P

以上是关于使用 intptr_t 代替 void*?的主要内容,如果未能解决你的问题,请参考以下文章

关于 uintptr_t和intptr_t 类型

为啥/何时使用 `intptr_t` 在 C 中进行类型转换?

intptr_tuintptr_t数据类型

intptr_tuintptr_t数据类型

使用 intptr_t 做一些算术运算

如何将 intptr_t 转换为字符串 [重复]