uintptr_t数据类型是什么?

uintptr_t是什么?它可以用来做什么?

279372 次浏览

它是一个无符号整数类型,大小与指针相同。当你需要对指针做一些不寻常的事情时——比如反转所有位(不要问为什么),你可以将其转换为uintptr_t,并将其操作为普通整数,然后再转换回来。

首先,在问这个问题的时候,uintptr_t并不在c++中。它在C99中,在<stdint.h>中,作为可选类型。许多c++ 03编译器确实提供了该文件。它也在c++ 11中,在<cstdint>中,它也是可选的,并且它引用C99的定义。

在C99中,它被定义为“一种无符号整数类型,其属性是任何指向void的有效指针都可以转换为这种类型,然后再转换回指向void的指针,并且结果将与原始指针进行比较”。

把这句话当真。它没有提到大小。

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

关于“什么是uintptr_t数据类型?”已经有很多好的答案。我将试着解决“它可以用来做什么?”在这篇文章中。

主要用于指针的位操作。记住,在c++中不能对指针执行按位操作。原因见为什么不能在C语言中对指针进行位操作,有办法解决这个问题吗?

因此,为了对指针进行位操作,需要将指针转换为uintptr_t类型,然后执行位操作。

这是我刚刚写的一个函数的例子,它是按位排他的,或者是将2个指针存储在一个异或链表中,这样我们就可以像一个双链表一样在两个方向上遍历,但不用在每个节点上存储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)添加一个非常好的用途,那就是编写可测试的嵌入式代码。

我主要编写针对各种arm和tensilica处理器的嵌入式代码。它们有不同的本地总线宽度,tensilica实际上是一个哈佛体系结构,具有不同宽度的独立代码和数据总线。

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

话虽如此,很多嵌入式代码都涉及到位处理和地址操作。我的大多数英特尔电脑都是64位的。所以如果你要测试地址操作代码,你需要一个通用对象来计算。因此,uintptr_t为你提供了一种机器独立的方法,在你尝试部署到目标硬件之前调试你的代码。

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

——编辑——

@chux指出,这不是标准的一部分,函数也不是c中的对象。然而,它通常是有效的,因为许多人甚至不知道这些类型,我通常会留下评论解释这个技巧。在SO中uintptr_t的其他搜索将提供进一步的解释。此外,我们在单元测试中做了一些在生产中永远不会做的事情,因为破坏东西是好事。