intptr_t
,uintptr_t
这两个数据类型是 ISO C99 定义的,具体代码在 linux 平台的 /usr/include/stdint.h
头文件中。
/* Types for `void *' pointers. */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned long int uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned int uintptr_t;
#endif
下不同的数据类型在不同字长机器上长度大小。
位数 | char | short | int | long | 指针 |
---|---|---|---|---|---|
16 | 1个字节8位 | 2个字节16位 | 2个字节16位 | 4个字节32位 | 2个字节16位 |
32 | 1个字节8位 | 2个字节16位 | 4个字节32位 | 4个字节32位 | 4个字节32位 |
64 | 1个字节8位 | 2个字节16位 | 4个字节32位 | 8个字节64位 | 8个字节64位 |
指针在32位平台和64位平台下均与 long
类型的长度一致,然而在16位机器上,long
为4个字节,而指针为2个字节。
因此,就可以发现 intptr_t
和 uintptr_t
定义的巧妙之处:
在64位机器上,intptr_t
为 long int
,uintptr_t
为 unsigned long int
。而在非64位机器上,intptr_t
为 int,uintptr_t
为 unsigned int
。
这样就可以保证 intptr_t
和 uintptr_t
的长度与机器的指针长度一致,因此在进行整数与指针的相互转换时可以用 intptr_t
进行过渡。
C语言指针用来保存变量或常量的地址,地址长度由处理器的位数决定。在windows程序中,经常用到句柄,其实就是一个地址,具备通用性,对底层进行了封装。 指针长度取决于使用的机器和编译器。64位机器的出现导致为不同数据类型分配的内存在长度上的差异变得明显。
指针相关的预定义类型
使用指针时经常用到以下四种预定义类型:
- size_t:用于安全地表示长度。
- ptrdiff_t:用于处理指针算术运算。
- intptr_t 和 uintptr_t:用于存储指针地址。
- size_t 类型表示 C 中任何对象所能达到的最大长度,它是无符号整数。
- size_t 用做 sizeof 操作符的返回值类型,同时也是很多函数的参数类型,包括 malloc 和 strlen。
intptr_t 和 uintptr_t:
intptr_t 和 uintptr_t 类型用来存放指针地址。
作用:通常用于将指针转换为整数,以及在整数形式下进行操作,直到再次将其转换为指针类型。
它们提供了一种可移植且安全的方法声明指针,而且和系统中使用的指针长度相同,对于把指针转化成整数形式来说很有用。当需要将指针作为整数运算时,将它转换成 intptr_t / uintptr_t 进行运算才是安全的。
避免把指针转换成整数。如果指针是64 位,整数只有4 字节时就会丢失信息。
#include <iostream>
#include <iomanip> // std::setfill() std::setw()
//#include "stdint.h" // uintptr_t
int main()
{
int a = 10;
int* p = &a;
uintptr_t p_addr = (uintptr_t)p;
std::cout << std::uppercase << std::hex << std::setfill('0') << "Address of p = 0x" << p_addr << std::endl;
// 恢复默认的格式设置
std::cout << std::defaultfloat << std::setfill(' ');
return 0;
}
uintptr_t 和 void * 的区别:
uintptr_t 表示一个整数地址,在 C 和 C++ 中前者是无符号整型数据类型,而后者是指向未知类型的指针类型,不能直接通过指针的类型进行转换和使用,因为 void* 无法进行加减操作,也无法进行指针的解引用。因此,两者是有明显区别的,uintptr_t 表示的是指针的地址,void* 表示的是指向某个内存地址的指针。