#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);
}
5条答案
按热度按时间2j4z5cfb1#
主要原因是,您不能在
void *
上执行按位操作,但可以在intptr_t
上执行相同的操作。在很多情况下,当你需要对一个地址执行位操作时,你可以使用
intptr_t
。但是,对于按位运算,最好的方法是使用
unsigned
的对应项uintptr_t
。正如@chux在other answer中提到的,指针比较是另一个重要方面。
此外,根据
C11
标准§7.20.1.4,FWIWjobtbby32#
还有一个语义上的考虑。
一个
void*
被认为是“指向某个东西”。尽管现代实用性很强,但指针并不是内存地址。好吧,它通常/可能/总是(!)包含一个地址,但它不是一个数字。它是一个指针。它指向一个东西。intptr_t
则不然,它是一个整数值,可以安全地转换为指针,这样你就可以把它用于老式的API,把它打包成一个pthread
函数参数,诸如此类。这就是为什么在
intptr_t
上比在void*
上可以做更多琐碎的事情,也是为什么应该通过使用适当的类型来实现自文档化。最终,几乎所有的东西都可能是整数(记住,你的计算机是处理数字的!);指针也可能是整数,但它们不是;它们之所以是指针,是因为它们有不同的用途;而且,理论上,它们可以是数字以外的东西。
jgwigjjp3#
uintptr_t
类型在编写内存管理代码时非常有用,这类代码希望用通用指针(void *
)与客户端通信,但在内部对地址进行各种运算。通过对
char *
进行操作,您可以做一些相同的事情,但不是所有事情,结果看起来像AnsiC之前的版本。不是所有的内存管理代码都使用
uintptr_t
-例如,BSD内核代码定义了一个具有类似属性的vm_offset_t
.但是,如果你正在编写调试malloc包,为什么要发明自己的类型呢?当您的
printf
中有%p
可用,并且正在编写需要在各种架构上以十六进制打印指针大小的整型变量的代码时,这也很有帮助。我发现
intptr_t
用处不大,除了可能作为强制转换时的中转站,以避免在同一强制转换中更改有符号性和整数大小的可怕警告(编写在所有相关体系结构上传递-Wall -Werror
的可移植代码可能有点困难)。sc4hvdpw4#
intptr_t有什么用?
使用示例:顺序比较。
比较指针是否相等不是问题。
其他比较运算如
>, <=
可以是UB. C11dr § 6.5.8/5关系运算符。因此,首先转换为
intptr_t
。[编辑]新例子:按指针值对指针数组排序。
[前例]使用示例:测试指针是否属于指针数组。
正如@M. M所评论的,上面的代码可能无法正常工作。但至少它不是UB。-只是不可移植的功能。我希望用它来解决this problem。
7kqas0il5#
(u)intptr_t
用于对指针进行算术运算,特别是位运算。但正如其他人所说,您几乎总是希望使用uintptr_t
,因为位运算在无符号中更好地完成。然而,如果您需要执行 * 算术右移 *,则必须使用intptr_t
**1。它通常用于在指针中存储数据,通常称为tagged pointerchar* tagged_address
,则需要在解引用它之前进行符号扩展因此,当指针的最低有效位为0时,它将右移以检索原始的31位有符号int
有关详细信息,请参阅
另一种用法是将有符号整数作为
void*
传递,这通常在简单的回调函数或线程中完成1当实现对有符号类型进行算术移位时
2个非常新的x86-64 CPU可能具有UAI/LAM support