Joh*_*ell 17 c pointers void-pointers
鉴于我需要在结构中存储"泛型"指针的值并且对指向的内存本身没有兴趣,我发现将它存储为intptr_t
比a 更为语义正确void*
.问题是a uintptr_t
是否更适合,并且当一个人更喜欢另一个人时?
unw*_*ind 10
这听起来很奇怪,因为它需要演员阵容.void *
C中的A 具有巨大的优势,它可以在没有强制转换的情况下转换为其他对象指针类型/从其他对象指针类型进行转换
uintptr_t
如果你想对指针的某些部分做一些事情,那么这可能是有意义的,你无法通过有符号整数(例如将它们向右移动)来做.
它主要是一种风格论证(优化编译器可能生成相同或非常相似的代码).但是,指针比较可能是一个棘手的问题.
记住,比纯粹的标准C指针比较仅对指向相同聚合数据的指针大致有意义.您可能不允许比较两个结果malloc
,例如保留已排序的指针数组.
我会保留它们void*
,或者作为uintptr_t
.签名intptr_t
有分隔负数和正数的不便,以及它们来自重要的应用程序指针,这可能不受欢迎.
请注意,a void*
不能被解除引用:作为一个uintptr_t
,您必须将其强制转换为对地址指向的数据执行有用的操作; 但是void*
指针可以传递给例程memset
PS.我假设一个普通的处理器(例如某些x86,PowerPC,ARM,......)具有平坦的虚拟地址空间.您可能会发现异国情调的处理器 - 可能是某些DSP - 具有非常显着的差异(并且可能intptr_t
并不总是有意义的;请记住在20世纪90年代的Cray Y-MP超级计算机sizeof(long*) != sizeof(char*)
;当时C99不存在,我不确定它<stdint.h>
是否可以在这样的机器上有意义)
您应该选择适合给定系统和程序的类型。大多数时候,指针是正地址值,在这种情况下uintptr_t
是正确的类型。但是有些系统使用负地址作为表达内核空间的一种方式,正如这里所解释的:指针(地址)可以为负吗?这就是为什么有两种不同类型的原因。
对于通用指针类型的(u)intptr_t
vs void*
,前者在坚固、专业的程序中更受欢迎。有许多与指针类型相关的问题/错误来源:
const
,这使得与该类型之间的指针转换有问题或定义不明确。void*
与其他指针类型之间的转换是隐式发生的,这使得与使用错误指针类型相关的错误很容易被忽视。这在 C++ 中已修复,但在 C 中仍然存在危险。以旧但经典的“我在 C90 中使用 malloc 时忘记包含 stdlib.h”错误为例。void*
. 这样做依赖于非标准编译器扩展。话虽如此,很多遗留代码都依赖于void
指针,在受限上下文中使用它们是完全没问题的。一些示例是依赖通用回调函数的规范代码:bsearch
、qsort
、 pthreads 等。
然而,我不建议void
在设计新的 C 程序时使用指针——在我看来,它们最好被视为过去的一个危险特性。现在存在更好和更安全的通用 C 编程方法,例如 C11 _Generic
,使用指定初始值设定项的技巧,将参数作为数组指针传递(到 VLA),在编译时检查边界static_assert
等。一些例子可以在我的回答中找到:如何创建类型安全的枚举?.