什么时候uintptr_t优先于intptr_t?

时间:2015-04-22 14:10:23

标签: c pointers void-pointers

鉴于要求我需要在结构中存储“泛型”指针的值并且对指向的内存本身没有兴趣,我发现将它存储为intptr_t在语义上更正确而不是void*。问题是uintptr_t是否更适合,一般情况下是否优先于另一种?

3 个答案:

答案 0 :(得分:8)

它主要是一种风格论证(优化编译器可能生成相同或非常相似的代码)。但是,指针比较可能是一个棘手的问题。

请记住,与纯粹的标准C指针相比,仅对指向相同聚合数据的指针大致有意义。您可能不允许比较malloc的两个结果,例如保留一个排序的指针数组。

我会将它们保留为void*,或者保留为uintptr_t。签名intptr_t有不方便分隔负数和正数,以及它们来自重要的应用程序指针,这可能不受欢迎。

请注意,void*无法取消引用:作为uintptr_t,您拥有来投射它以对地址指向的数据执行有用的操作;但void*指针可以传递给memset

等例程

PS。我假设一个普通的处理器(例如某些x86,PowerPC,ARM,......)具有平坦的虚拟地址空间。您可能会发现异乎寻常的处理器 - 可能是某些DSP - 具有非常显着的差异(并且intptr_t可能并不总是有意义的;请记住在20世纪90年代Cray Y-MP超级计算机sizeof(long*) != sizeof(char*);当时{ {3}}不存在,我不确定<stdint.h>在这些机器上是否有意义。

答案 1 :(得分:3)

您应该选择适合给定系统和程序的类型。在大多数情况下,指针是正地址值,在这种情况下,uintptr_t是正确的类型。但是某些系统使用负地址来表示内核空间,如此处所述:Can a pointer (address) ever be negative?这就是为什么存在两种不同类型的原因。


对于(u)intptr_tvoid*(对于通用指针类型)而言,前者在坚固耐用的专业程序中是首选。与指针类型相关的问题/错误来源很多:

  • 不同指针类型的所有方式通常都是彼此不兼容的,并且不能混叠。这是对象指针和函数指针的问题。
  • 您经常会遇到类型限定符,例如const,这会使往/从该类型的指针转​​换产生疑问或定义不明确。
  • void*和其他指针类型之间的转换是隐式发生的,这使得与使用错误的指针类型有关的错误很容易被忽视。该问题在C ++中已修复,但在C语言中仍然存在危险。例如,古老而经典的“我忘记了在C90中使用malloc时包含stdlib.h”错误。
  • 对指针执行算术会带来很多陷阱,因为您只能安全地对指向已分配数组的指针进行算术。但是,嵌入式系统工作人员都知道,除了指向数组之外,还有很多其他原因通常可以拥有一个内存地址。
  • 不能甚至在void*上执行指针算术运算。这样做依赖于非标准的编译器扩展。

话虽这么说,很多遗留代码都依赖于void指针,并且在受限的上下文中使用它们是完全可以的。一些示例是依赖于通用回调函数的规范代码:bsearchqsort,pthread和类似的东西。

但是,在设计新的C程序时,我不建议使用void指针-在我看来,最好将它们视为过去的危险特性。如今,存在更好,更安全的通用C编程方法,例如C11 _Generic,使用指定的初始化程序的技巧,将参数作为数组指针传递给VLA,在编译时使用static_assert进行边界检查等。可以在我的答案中找到一些示例:How to create type safe enums?

答案 2 :(得分:2)

如果你想算术地操纵值(例如,加密它),你可以更灵活地使用无符号类型(算术环绕)而不是带符号类型(算术溢出会给出未定义的行为)。