如果我想对指针进行常规算术(而不是指针算术),我应该使用uintptr_t吗?

时间:2013-10-20 01:55:10

标签: c pointers

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

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

3 个答案:

答案 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)中,最重要的指针位保留给系统。如果您有两个指针ab仅在该位上有所不同,那么将这些指针与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);