什么是uintptr_t
,什么可以把它用于?
什么是uintptr_t
,什么可以把它用于?
Answers:
uintptr_t
是能够存储数据指针的无符号整数类型。通常,这意味着它与指针的大小相同。
想要一个可以容纳体系结构的指针类型的整数类型的常见原因是对指针执行特定于整数的操作,或者通过将其提供为整数“ handle”来掩盖指针的类型。
size_t
只需要足以容纳最大对象的大小即可,并且可以小于指针。这将预期对分段架构像8086(16位size_t
,但32位void*
)
ptrdiff_t
。uintptr_t
不是为了那个。
unsigned int
通常不够大。但是它可能足够大。该类型专门用于删除所有“假定”。
在提出问题时,第一件事uintptr_t
不是C ++。在C99中的中<stdint.h>
,作为可选类型。许多C ++ 03编译器确实提供了该文件。它也在C ++ 11中的中<cstdint>
,该处也是可选的,它的定义参考C99。
在C99中,它被定义为“一个无符号整数类型,具有以下属性:可以将任何有效的指向void的指针转换为该类型,然后再转换回指向void的指针,结果将与原始指针进行比较”。
以此来表达它的意思。它没有说明尺寸。
uintptr_t
的大小可能与相同void*
。可能更大。可以想象,它可能会更小,尽管这样的C ++实现方式是错误的。例如,在一个假设的平台上,其中void*
有32位,但仅使用了24位虚拟地址空间,您可以拥有一个uintptr_t
满足要求的24位。我不知道为什么实现会这样做,但是标准允许这样做。
void*
。但是,它会影响将来的可能方向,尤其是如果您想更改为使用实际上只是整数句柄而不是根本没有转换指针的东西。
typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;
。相反:callback.dataPtr = (void*)val
。另一方面,您当然void*
必须将其强制转换回int
。
这是一个无符号整数类型,恰好等于指针的大小。每当您需要对指针执行一些异常操作时(例如将所有位都求反(不要问为什么)),都将其uintptr_t
强制转换为普通整数,然后将其转换为整数。
void*
指针值uintptr_t
再次来回转换会产生一个void*
与原始指针相等的值。uintptr_t
通常与大小相同void*
,但不能保证,也不能保证转换后的值的位具有任何特殊含义。并且不能保证它可以保存转换后的指向函数的指针值而不会丢失信息。最后,它不能保证存在。
对于“什么是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));
}
冒着获得另一个死灵法师徽章的风险,我想为uintptr_t(甚至是intptr_t)添加一个很好的用法,那就是编写可测试的嵌入式代码。我主要针对各种手臂和当前的tensilica处理器编写嵌入式代码。它们具有各种本机总线宽度,而tensilica实际上是哈佛架构,具有可以不同宽度的单独的代码和数据总线。我对大多数代码使用测试驱动的开发风格,这意味着我对所编写的所有代码单元都进行了单元测试。在实际目标硬件上进行单元测试很麻烦,因此我通常使用Ceedling和GCC在Windows或Linux的基于Intel的PC上编写所有内容。话虽这么说,许多嵌入式代码都涉及到纠结和地址操纵。我的大多数Intel机器都是64位的。因此,如果要测试地址处理代码,则需要一个通用对象来进行数学运算。因此,在尝试部署到目标硬件之前,uintptr_t为您提供了一种与机器无关的调试代码的方式。另一个问题是对于某些机器,甚至某些编译器上的内存模型,函数指针和数据指针的宽度不同。在这些机器上,编译器甚至可能不允许在这两个类之间进行强制转换,但是uintptr_t应该能够保留其中任何一个。