1

假设我有一个指向 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

我被告知不要使用常规整数并假装它们是指针。

4

3 回答 3

2

您不能uintptr_t以可移植的方式对 a 执行算术运算。以下是该类型的定义方式:

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(真),并将它们减去a-b将返回 0。但是如果您将这些指针转换为uintptr_t值并比较它们,==将返回 0,并将-返回非 0。

于 2013-10-20T11:26:31.493 回答
1

通常,您在此处转换为char *unsigned char *执行您的算术 - 因为sizeof(char)==1根据定义,您实际上将执行“常规”算术,其好处是您不会以任何方式离开“指针域”并且您不会违反别名规则。

于 2013-10-20T02:02:49.943 回答
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);
于 2013-10-20T02:03:03.537 回答