我知道它是一个整数类型,可以在不丢失数据的情况下强制转换为指针,但为什么我要这样做呢?使用整数类型超过void*
来保持指针和THE_REAL_TYPE*
用于指针算术有什么好处?
修改
标记为“已经被问到”的问题没有回答这个问题。问题是,如果使用intptr_t
作为void*
的一般替换是一个好主意,那里的答案似乎是“不要使用intptr_t”,所以我的问题仍然有效:什么会是intptr_t
的一个很好的用例吗?
答案 0 :(得分:15)
主要原因是,您无法对void *
执行按位操作,但您可以在intptr_t
上执行相同的操作。
在许多情况下,您需要对地址执行按位操作,您可以使用intptr_t
。
但是,对于按位运算,最好的方法是使用unsigned
对应的uintptr_t
。
如other answer @chux所述,指针比较是另一个重要方面。
另外,FWIW,按照C11
标准,§7.20.1.4,
这些类型是可选的。
答案 1 :(得分:7)
intptr_t有什么用?
使用示例:订单比较。
比较指向平等的指针不是问题
其他比较操作如>, <=
可能是UB。 C11dr§6.5.8/ 5关系运算符。
因此,首先转换为intptr_t
。
[编辑]新示例:按指针值对指针数组进行排序。
int ptr_cmp(const void *a, const void *b) {
intptr_t ia = (intptr) (*((void **) a));
intptr_t ib = (intptr) (*((void **) b));
return (ia > ib) - (ia < ib);
}
void *a[N];
...
qsort(a, sizeof a/sizeof a[0], sizeof a[0], ptr_cmp);
[前例] 示例用法:测试指针是否为指针数组。
#define N 10
char special[N][1];
// UB as testing order of pointer, not of the same array, is UB.
int test_special1(char *candidate) {
return (candidate >= special[0]) && (candidate <= special[N-1]);
}
// OK - integer compare
int test_special2(char *candidate) {
intptr_t ca = (intptr_t) candidate;
intptr_t mn = (intptr_t) special[0];
intptr_t mx = (intptr_t) special[N-1];
return (ca >= mn) && (ca <= mx);
}
如@M.M所述,上述代码可能无法正常运行。但至少它不是UB。 - 只是非便携式功能。我希望用它来解决this problem。
答案 2 :(得分:6)
在编写内存管理代码时,uintptr_t类型非常有用。这种代码想要通用通用指针(void *)与客户端进行通信,但内部对地址进行各种算术运算。
你可以通过操作char *而不是一切来做同样的事情,结果看起来像前Ansi C.
并非所有内存管理代码都使用uintptr_t - 例如,BSD内核代码定义了具有类似属性的vm_offset_t。但如果你正在写作,调试malloc包,为什么要发明自己的类型?
如果你的printf中有%p可用,并且正在编写需要在各种体系结构上以十六进制打印指针大小的整数变量的代码,这也很有用。
我发现intptr_t相当不太有用,除了在投射时可能作为一种方式站,以避免在同一演员阵容中改变签名和整数大小的恐惧警告。 (编写在所有相关体系结构上传递-Wall -Werror的可移植代码可能会有点费力。)
答案 3 :(得分:6)
还有一个语义上的考虑。
一个void*
应该指向某事。尽管有现代实用性,但指针不是存储器地址。好的,它通常/大概/总是(!)持有一个,但不是数字。这是一个指针。它指的是事物。
intptr_t
没有。这是一个整数值,可以安全地与指针进行转换,因此您可以将其用于旧式API,并将其包装到pthread
函数参数中,诸如此类。
这就是为什么在intptr_t
上可以做的事比在void*
上能做的事要多的原因,也是为什么应该使用适合工作的类型来进行自我记录的原因。
最终,几乎所有都可以为整数(请记住,您的计算机可以使用数字!)。指针可能是整数。但事实并非如此。它们是指针,因为它们的用途不同。而且,从理论上讲,它们可能不是数字。
答案 4 :(得分:1)
(u)intptr_t
用于对指针进行算术运算,特别是按位运算。但正如其他人所说,您几乎总是想使用 uintptr_t
,因为按位运算最好在无符号中完成。但是,如果您需要进行算术右移,那么您必须使用intptr_t
。通常用于在指针中存储数据,通常称为tagged pointer
在 x86-64 中,您可以将高 16/7 位用于数据,但您必须手动将符号扩展到 make the pointer canonical,因为它目前没有用于忽略高位 { {3}}。因此,例如,如果您有 char* address
,那么您需要在取消引用它之前执行此操作
char* pointer = (char*)((intptr_t)address << 16 >> 16);
32 位 Chrome V8 引擎使用 like in ARM where smi (small integer) optimization
|----- 32 bits -----|
Pointer: |_____address_____w1| # Address to object, w = weak pointer
Smi: |___int31_value____0| # Small integer
因此,当指针的最低有效位为 0 时,它将右移以检索原始的 31 位有符号整数
int v = (intptr_t)address >> 1;
欲了解更多信息,请阅读
另一种用法是将有符号整数作为 void*
传递,这通常在回调函数或线程中完成
void* my_thread(void *arg)
{
intptr_t val = (intptr_t)arg;
// Do something
}
int main()
{
pthread_t thread1;
intptr_t some_val = -2;
int r = pthread_create(&thread1, NULL, my_thread, (void*)some_val);
}