什么是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将提供进一步的解释。此外,我们在单元测试中做了一些在生产中永远不会做的事情,因为破坏东西是好事。
首先,在问这个问题的时候,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,并把它作为一个通常的整数来操作,然后再转换回来。
Uintptr_t是一个无符号整数类型,能够存储一个数据指针(是否可以保存函数指针未指定)。这通常意味着它与指针的大小相同。
在c++ 11及以后的标准中可选地定义它。
需要一个可以保存体系结构指针类型的整数类型的一个常见原因是对指针执行特定于整数的操作,或者通过将指针提供为整数“句柄”来模糊指针的类型。