假设我有一个指向int的指针,其值为0x5。我想在该值上添加一个0x3的偏移量。
我应该这样做(方法A):
int* pointer = 0x5;
int offset = 0x3;
pointer = pointer + (offset/sizeof(int)); // pointer is now equal to 0x8
或像这样(方法B):
uintptr_t pointer = 0x5;
pointer = pointer + 0x3;
int* ptr = (int*) pointer; // pointer is now equal to 0x8
我在看到这个问题后问这个:What is uintptr_t data type
我被告知不要使用常规整数并假装它们是指针。
答案 0 :(得分:2)
您无法以便携方式对uintptr_t
执行算术运算。以下是该类型的定义方式:
7.18.1.4能够保存对象指针的整数类型
以下类型指定一个带符号的整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将等于原始指针:
intptr_t
以下类型指定一个无符号整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将与原始指针进行比较:
uintptr_t
这些类型是可选的。
请注意,规范没有说明如何表示指针。在大多数实现中,对uintptr_t
值的算术可能会有预期的结果,但如果您希望代码是可移植的,则应该使用指针算法,因为它具有良好指定的语义。
uintptr_t
算术可能具有意外行为的平台示例是IBM的z / OS。在传统的31位模式(是的,31)中,最重要的指针位保留给系统。如果您有两个指针a
和b
仅在该位上有所不同,那么将这些指针与a==b
进行比较将按预期返回1(true),并使用a-b
减去它们将返回0.但如果您将这些指针转换为uintptr_t
值并进行比较,==
将返回0,而-
将返回非0。
答案 1 :(得分:1)
通常情况下,你会转向char *
或unsigned char *
并在此处进行算术运算 - 因为根据定义sizeof(char)==1
,你实际上会做“常规”算术,其好处是你没有以任何方式离开“指针域”而你没有违反别名规则。
答案 2 :(得分:1)
int *pointer = 0x5;
int offset = 0x3;
pointer = pointer + (offset/sizeof(int));
假设sizeof(int) == 4
,除法将计算为0,指针不会改变。如果您的不除以sizeof(int)
,则指针将按3*sizeof(int)
char
个单位推进。
uintptr_t pointer = 0x5;
pointer = pointer + 0x3;
int *ptr = (int *) pointer;
事实上这确实将ptr
设置为ptr = (int *)0x8
所具有的相同值。 (绝大多数情况下,这不是指向任何事物的有效指针。)
上述两种方法都不是用正常方式在C中执行此类操作。惯用技术是转换为char *
并返回:
int *pointer = 0x5;
ptrdiff_t offset = 0x3;
pointer = (int *) (((char *)pointer) + offset);
assert (pointer == (int *)0x8);