什么是uintptr_t数据类型

dim*_*mba 233 c++ types pointers

什么是uintptr_t以及它可以用于什么?

Ste*_*sop 225

首先,在提出问题的时候,问题uintptr_t不在于C++.它在C99中<stdint.h>,作为可选类型.许多C++ 03编译器都提供该文件.它也在C++ 11中,在<cstdint>那里它也是可选的,它引用了C99的定义.

在C99中,它被定义为"无符号整数类型,其属性是任何有效的指向void的指针都可以转换为此类型,然后转换回指向void的指针,结果将与原始指针进行比较".

这意味着它的意思.它没有说明大小.

uintptr_t可能与a的大小相同void*.它可能更大.可以想象它可以更小,尽管这样的C++实现有些不正常.例如,在一些void*32位的假设平台上,但只使用了24位的虚拟地址空间,您可以使用uintptr_t满足要求的24位.我不知道为什么一个实现会这样做,但标准允许它.

  • 感谢"<stdint.h>".由于uintptr_t声明,我的应用程序没有编译.但是当我阅读你的评论时,我添加了"#include <stdint.h>",现在它的确有效.谢谢! (7认同)
  • 将指针强制转换为int的另一个常见用例是创建一个隐藏指针的不透明句柄.这对于从API返回对象的引用非常有用,您希望将对象保持对库的私有性,并防止应用程序访问它.然后,应用程序被迫使用API​​对对象执行任何操作 (4认同)
  • @JoelCunningham:这有效但与使用`void*`没有什么不同.但是,它会影响可能的未来方向,特别是如果您可能希望更改为使用实际上只是整数句柄的东西,而不是转换指针. (3认同)
  • 例如,[分配对齐的内存](http://stackoverflow.com/q/227897/183120)以及其他用途? (2认同)
  • @CiroSantilli乌坎事件2016六四事件法轮功一个常见的用例是只将一个int传递给一个API,它需要一个void*来通用数据.为你节省了击键`typedef struct {int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr =&whyAmINotDoneYet;`.相反:`callback.dataPtr =(void*)val`.另一方面,你当然得到`void*`并且必须把它转回`int`. (2认同)

Dre*_*ann 181

uintptr_t是无符号整数类型,能够存储指针.这通常意味着它与指针的大小相同.

它可选地在C++ 11和更高版本的标准中定义.

想要一个可以保存体系结构指针类型的整数类型的一个常见原因是对指针执行整数特定的操作,或者通过将指针提供为整数"句柄"来模糊指针的类型.

编辑:请注意,史蒂夫杰索普有一些非常有趣的额外细节(我不会偷)在另一个答案在这里为你迂腐的类型:)

  • 请注意,`size_t`只需要足以容纳最大对象的大小,并且可以小于指针.这将在8086(16位`size_t`,但32位`void*`)这样的分段体系结构上得到应用. (51认同)
  • 为了表示两个指针之间的差异,你有`ptrdiff_t`.`uintptr_t`不是故意的. (3认同)
  • @jalf:对于差异,是的,但是对于*distance*,你会想要一个无符号类型. (3认同)
  • @MarcusJ` unsigned int`通常不够大.但它可能足够大.此类型专门用于删除所有*"假设"*. (2认同)

sha*_*oth 19

它是一个无符号整数类型,与指针的大小完全相同.每当你需要用指针做一些不寻常的事情时 - 例如反转所有位(不要问为什么)你将它转换为uintptr_t并将其作为通常的整数进行操作,然后再回滚.

  • 当然你可以这样做,但那当然是未定义的行为.我相信那时你只能对uintptr_t进行投射的结果就是不加改变地传递它并将其抛回 - 其他一切都是UB. (5认同)
  • @sleske那不是真的.在具有自对齐类型的机器上,指针的两个最低有效位将为零(因为地址是4或8的倍数).我见过利用它压缩数据的程序.. (3认同)
  • @saadtaame:我只是根据C标准*指出这是UB*.这并不意味着它无法在某些系统上定义 - 编译器和运行时可以自由地为标准C中的UB定义特定行为.因此没有矛盾:-). (3认同)
  • 它不一定完全是指针的大小.所有的标准保证是将`void*`指针值转换为`uintptr_t`并再次返回产生一个'void*'值,该值与原始指针相比较.`uintptr_t`通常与`void*`的大小相同,但不保证,也不保证转换后的值的位具有任何特定含义.并且无法保证它可以保存转换的指针到函数值而不会丢失信息.最后,它不能保证存在. (2认同)

BGR*_*BGR 12

"什么是uintptr_t数据类型"部分已经有很多很好的答案.我会尝试解决"它可以用于什么?" 这篇文章的一部分.

主要用于指针的按位操作.请记住,在C++中,无法对指针执行按位操作.由于原因,请参阅为什么不能对C中的指针进行按位操作,有没有办法解决这个问题?

因此,为了对指针进行按位操作,需要将指针转换为类型unitpr_t,然后执行按位运算.

下面是一个函数的例子,我刚刚编写为按位排序或2个指针存储在XOR链表中,这样我们可以像双向链表一样遍历两个方向,但不会在每个节点中存储2个指针.

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }
Run Code Online (Sandbox Code Playgroud)


bd2*_*357 5

冒着获得另一个死灵法师徽章的风险,我想为uintptr_t(甚至intptr_t)添加一个非常好的用途,那就是编写可测试的嵌入式代码。

我主要编写针对各种 arm 和当前 tensilica 处理器的嵌入式代码。它们具有不同的原生总线宽度,并且 Tensilica 实际上是一种哈佛架构,具有不同宽度的单独代码和数据总线。

我对我的大部分代码使用测试驱动的开发风格,这意味着我对我编写的所有代码单元进行单元测试。在实际目标硬件上进行单元测试很麻烦,因此我通常使用 Ceedling 和 GCC 在 Windows 或 Linux 中的基于 Intel 的 PC 上编写所有内容。

话虽如此,许多嵌入式代码都涉及位处理和地址操作。我的大部分 Intel 机器都是 64 位的。因此,如果您要测试地址操作代码,则需要一个通用对象来进行数学运算。因此,uintptr_t在您尝试部署到目标硬件之前,它为您提供了一种独立于机器的调试代码的方式。

另一个问题是对于某些机器甚至某些编译器上的内存模型,函数指针和数据指针的宽度不同。在这些机器上,编译器甚至可能不允许在两个类之间进行转换,但uintptr_t应该能够保持。

- 编辑 -

@chux 指出,这不是标准的一部分,函数也不是 C 中的对象。但是它通常可以工作,而且由于很多人甚至不知道这些类型,我通常会发表评论来解释这个技巧。SO on 中的其他搜索uintptr_t将提供进一步的解释。我们还在单元测试中做一些我们在生产中永远不会做的事情,因为打破东西是好的。