uintptr_t
是什么,它可以用来做什么?
首先,当问题被提出时,C++中没有 uintptr_t
这个类型,它是在 C99 标准的 <stdint.h>
中作为一个可选类型定义的。许多 C++03 编译器提供了这个文件。它也出现在 C++11 中,在 <cstdint>
中也是作为一个可选类型,而且它的定义参考了 C99。
在 C99 中,它被定义为“一种无符号整数类型,其特性是任何指向 void 的有效指针都可以转换为此类型,然后再转换回 void 指针,并且结果将与原始指针相等”。
只要理解字面含义就好,它并没有说什么关于大小的事情。
uintptr_t
可能与 void*
大小相同。它可能更大。它也可能更小,尽管这样的 C++ 实现有些奇怪。例如,在某些假设的平台上,void*
是32位,但只使用了24位虚拟地址空间,你可以有一个24位的 uintptr_t
来满足这个要求。我不知道为什么会有这样的实现,但标准允许这样做。
typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;
。相反,使用callback.dataPtr = (void*)val
。在另一方面,您当然会得到void*
并且必须将其转换回int
。 - Francesco Dondiuintptr_t
是一种无符号整型,能够存储一个数据指针 (是否可以保存函数指针未指定)。通常来说,这意味着它的大小与指针相同。
希望拥有一个整型类型能够保存计算机架构的指针类型,通常是为了在指针上执行整数特定操作,或者通过将其提供为整数“句柄”来模糊指针的类型。
size_t
只需要足以容纳最大对象的大小,并且可以比指针更小。在类似于 8086 的分段体系结构中,这是可以预期的(size_t
是 16 位,但 void*
是32位)。 - MSaltersptrdiff_t
。而 uintptr_t
不适用于此。 - jalfunsigned int
通常不够大。但它可能足够大。这种类型的存在是为了消除所有的“假设”。 - Drew Dormann这是一个无符号整数类型,大小正好与指针相同。每当需要对指针进行不寻常的操作时 - 比如颠倒所有位(不要问为什么),您将其转换为 uintptr_t
并像处理普通的整数一样进行操作,然后再转换回去。
void*
指针值转换为 uintptr_t
,再转回 void*
值后与原始指针相等。uintptr_t
的大小通常与 void*
相同,但不能保证,也没有任何保证转换后的值的位具有特定含义。并且不能保证它可以保存转换后的函数指针值而不会丢失信息。最后,也不能保证其存在。 - Keith Thompson已经有许多很好的回答了 "uintptr_t是什么数据类型?",在这篇文章中,我将尝试回答它的用途。
主要用于指针的按位操作。请记住,在C++中,不能对指针执行按位操作。原因请参见为什么不能在C语言中对指针执行按位操作,是否有解决方法?
因此,为了对指针执行按位操作,需要将指针强制转换为uintptr_t类型,然后执行按位操作。
以下是一个我刚刚编写的函数示例,用于对两个指针进行按位异或运算,以存储在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
为您提供了一种在尝试部署到目标硬件之前调试代码的机器无关方式。 另一个问题是对于某些机器甚至某些编译器上的内存模型,函数指针和数据指针具有不同的宽度。在这些机器上,编译器甚至可能不允许在两个类之间进行强制转换,但是 uintptr_t
应该能够容纳任何一个。uintptr_t
适用于将void *
转换为对象指针,以及将对象指针转换为void *
。函数指针可能无法与void *
往返(例如,函数指针比void *
大),因此也可能无法适应uintptr_t
。 - chux - Reinstate Monica
std::uintptr_t
和std::intptr_t
。 - alfC