指针偏移 [英] pointer offsetting

查看:76
本文介绍了指针偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

a)如果我这样做

指针= pointer_to_safe_thing - 1000;

指针[1000] == pointer_to_safe_thing [0];


然后

我*不*访问无效内存。我在数学意义上也不正确。

然而,pointer_to_safe_memory的结果 - 1000操作

产生指针可能是未定义的。因为我不知道是否指针

像整数一样环绕?


b)如果我这样做(假设数组是整数)

intprt_t i;

i = pointer_to_safe_thing - 1000;

(指针=(int *)(i + 1000))== pointer_to_safe_thing [0];


然后

它应该是正确的。对于整数环绕(应该?)。


我是否正确?我觉得这取决于什么类型的数字系统

计算机使用。

提前谢谢。

解决方案

c.***@seznam.cz 写道:


a)如果我这样做

指针= pointer_to_safe_thing - 1000;

指针[1000] == pointer_to_safe_thing [0];


然后

我*不*访问无效内存。我在数学意义上也不正确。

然而,pointer_to_safe_memory的结果 - 1000操作

产生指针可能是未定义的。因为我不知道指针

是否像整数一样环绕?



对,评估表达式pointer_to_safe_thing - 1000调用

未定义的行为(注意:* not *只是一个未定义的值)。这个

并不一定与环绕有任何关系;行为

未定义,因为标准是这样说的。


b)如果我这样做(假设数组是整数)

intprt_t i;

i = pointer_to_safe_thing - 1000;

(指针=(int *)(i + 1000))== pointer_to_safe_thing [0];


然后

它应该是正确的。对于整数环绕(应该?)。



我不太清楚你在这做什么。推测intprt_t对于intptr_t来说是一个

的错字。恰好有一个类型的名字,在< stdint.h>中声明为

;它是一个有符号整数类型,能够保持指针

值。 ``pointer_to_safe_thing - 1000''''的结果是

指针类型,而不是整数类型。转让是非法的;有没有

没有从指针到整数的隐式转换。


如果你通过添加一个强制转换使其合法化,那么你得到一些任意的

整数值;所有你知道的是你将相同的

值转换回指针类型并返回原始指针值。

(实际上对于intptr_t,该保证仅适用于无效*。)


如果intptr_t是一个指针类型(int *?),那么你有

与你的问题完全相同第一个例子。


如果您可以使用实际编译的代码来重构您的第二个示例,我们可以帮助您确定行为是否为

定义。我的猜测是,如果没有产生与你的第一个例子相当的东西,你将无法做到这一点。

$ b $我是对的吗?我觉得这取决于什么类型的数字系统

计算机使用。



这可能取决于任何数量的东西。标准说某些操作的行为是未定义的;它没有必要

说出原因。

这是另一个可能相关或不相关的例子和/或

具有启发性:


int obj;

int * valid_pointer =& obj;

(valid_pointer + 1000) - 1000; / *未定义的行为* /

valid_pointer + 1000 - 1000; / *相当于上面的* /

valid_pointer +(1000 - 1000); / * ok * /


-

Keith Thompson(The_Other_Keith) ks ***@mib.org < http://www.ghoti.net/~kst>

圣地亚哥超级计算机中心< *< http://users.sdsc .edu / ~kst>

我们必须做点什么。这是事情。因此,我们必须这样做。

- Antony Jay和Jonathan Lynn,是部长


非常感谢你们解释。


11月21日,21:56,Keith Thompson< ks ... @ mib.orgwrote:


c .... @ seznam.cz写道:


b)如果我这样做(假设数组是整数)

intprt_t i ;

i = pointer_to_safe_thing - 1000;

(指针=(int *)(i + 1000))== pointer_to_safe_thing [0];


then

应该是正确的。对于整数环绕(应该?)。



我不太清楚你在这做什么。推测intprt_t对于intptr_t来说是一个

的错字。恰好有一个类型的名字,在< stdint.h>中声明为

;它是一个有符号整数类型,能够保持指针

值。



是的,我是能够保持指针值的整数类型。对不起我

拼写错误。


`pointer_to_safe_thing - 1000''''的结果是

指针类型,不是整数类型。转让是非法的;有没有

没有从指针到整数的隐式转换。



谢谢我盲目地推测,对于这种类型它已经完成;)现在我

检查了

it是不是真的。


如果你通过添加一个演员来使它合法,那么你得到一些任意的

整数值;所有你知道的是你将相同的

值转换回指针类型并返回原始指针值。

(实际上对于intptr_t,该保证仅适用于无效*。)



现在我认为安全的方式可能是这样的:


object_t * p =& obj;

object_t * newptr = NULL; / *仅用于取消引用* /

uintptr_t vp = 0;


vp =(intptr)(void *)p;

vp = vp + INTPTR_MAX * sizeof(* p); / *溢出+保持对齐* /

newptr =(object_t *)(void *)(vp - INTPTR_MAX * sizeof(* p));

断言(newptr == p);


a)如果我使用intptr_t代替,则无法保证环绕(这是

签名值!)?

b)是否需要将值*转换为将值转移到

uintptr_t?

c)我是如何使用它来逐步调整大小(* p)正确吗?

步进指针类型的模拟ala

array [5] = array + 5 =(char *)array + 5 *(sizeof(array) [0])/

sizeof(char))?


c。*** @ seznam.cz 写道:


非常感谢您的解释。



[...]


现在我认为安全的方式可能是这样的:



安全的做法是什么?


object_t * p =& obj;

object_t * newptr = NULL; / *仅用于解除引用* /

uintptr_t vp = 0;



您为newptr和vp赋值;为什么要初始化它们?


vp =(intptr)(void *)p;



我认为你的意思是:


vp =(uintptr_t)(void *)p;


这通过从有效的

指针值转换获得有效的uintptr_t值。到目前为止,非常好。


vp = vp + INTPTR_MAX * sizeof(* p); / *溢出+保持对齐* /



您可以将void *值转换为uintptr_t。将结果转换为

返回void *可以保证返回原始的void *值。

这是*唯一*保证的东西。如果你以任何方式修改

uintptr_t值,将其转换回void *是没有意义的

(即使它恰好在你的平台上运行)。你可以做任何事情

你喜欢它*作为整数*,但你已经失去与

任何有意义的指针值的关联。


我无法弄清楚上述语句应该做什么。

首先,你要混合intptr_t和uintptr_t值。
< blockquote class =post_quotes>
newptr =(object_t *)(void *)(vp - INTPTR_MAX * sizeof(* p));



垃圾输入,垃圾输出。


assert(newptr == p);


a)如果我使用intptr_t代替,则无法保证环绕(这是

签名值!)?



由于uintptr_t是无符号类型,因此算术运算具有回绕性

语义。由于intptr_t已签名,因此overflow会调用undefined

行为。这些都不是以任何便携的方式与指针之间的关系相关。


b)这是否为传递值所必需的* * ,

uintptr_t?



我是这么认为的。


c)我是如何使用它来逐步调整尺寸(* p)正确吗?

步进指针类型的模拟ala

array [5] = array + 5 =(char *)array + 5 *(sizeof(array) [0])/

sizeof(char))?



不,虽然它可能适用于您的平台。


-

Keith Thompson(The_Other_Keith) ks***@mib.org < http://www.ghoti.net/~kst>

圣地亚哥超级计算机中心< *< http://users.sdsc.edu/~kst>

我们必须做点什么。这是事情。因此,我们必须这样做。

- Antony Jay和Jonathan Lynn,是部长


a) If i do
pointer = pointer_to_safe_thing - 1000;
pointer[1000] == pointer_to_safe_thing[0];

then
I am *not* accessing invalid memory. Nor i am incorrect in
mathematical sense.
Nevertheless outcome of pointer_to_safe_memory - 1000 operation
yielding pointer may be undefined. For i do not know whether pointers
wraparound like integers?

b) And if i do (lets say array is integer)
intprt_t i;
i = pointer_to_safe_thing - 1000;
(pointer = (int*) (i+1000) ) == pointer_to_safe_thing[0];

then
It should be correct. For integers wraparound (should?).

Am i correct? I feel that it depends on what type of number system
computer uses.
Thank you in advance.

解决方案

c.***@seznam.cz writes:

a) If i do
pointer = pointer_to_safe_thing - 1000;
pointer[1000] == pointer_to_safe_thing[0];

then
I am *not* accessing invalid memory. Nor i am incorrect in
mathematical sense.
Nevertheless outcome of pointer_to_safe_memory - 1000 operation
yielding pointer may be undefined. For i do not know whether pointers
wraparound like integers?

Right, evaluating the expression pointer_to_safe_thing - 1000 invokes
undefined behavior (note: *not* just an undefined value). This
doesn''t necesssarily have anything to do with wraparound; the behavior
is undefined because the standard says so.

b) And if i do (lets say array is integer)
intprt_t i;
i = pointer_to_safe_thing - 1000;
(pointer = (int*) (i+1000) ) == pointer_to_safe_thing[0];

then
It should be correct. For integers wraparound (should?).

I''m not quite sure what you''re doing here. Presumably intprt_t is a
typo for intptr_t. There happens to be a type by that name, declared
in <stdint.h>; it''s a signed integer type capable of holding pointer
values. The result of ``pointer_to_safe_thing - 1000'''' is of a
pointer type, not an integer type. The assignment is illegal; there''s
no implicit conversion from pointers to integers.

If you make it legal by adding a cast, then you get some arbitrary
integer value; all you know about it is that you ca convert the same
value back to a pointer type and get back the original pointer value.
(Actually for intptr_t that guarantee applies only to void*.)

If intptr_t is meant to be a pointer type (int*?), then you have
exactly the same problem as in your first example.

If you can reconstruct your second example with code that will
actually compile, we can help you figure out whether the behavior is
defined. My guess is that you won''t be able to do so without
producing something that''s equivalent to your first example.

Am i correct? I feel that it depends on what type of number system
computer uses.

It could depend on any number of things. The standard says that the
behavior of certain operations is undefined; it doesn''t necessarily
say why.

Here''s another example that may or may not be relevant and/or
instructive:

int obj;
int *valid_pointer = &obj;
(valid_pointer + 1000) - 1000; /* undefined behavior */
valid_pointer + 1000 - 1000; /* equivalent to the above */
valid_pointer + (1000 - 1000); /* ok */

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"


Thanks You both much for explanation.

On 11 íj, 21:56, Keith Thompson <ks...@mib.orgwrote:

c....@seznam.cz writes:

b) And if i do (lets say array is integer)
intprt_t i;
i = pointer_to_safe_thing - 1000;
(pointer = (int*) (i+1000) ) == pointer_to_safe_thing[0];

then
It should be correct. For integers wraparound (should?).


I''m not quite sure what you''re doing here. Presumably intprt_t is a
typo for intptr_t. There happens to be a type by that name, declared
in <stdint.h>; it''s a signed integer type capable of holding pointer
values.

Yes, i ment integer type capable of holding pointer value. Sorry i
misspelled.

The result of ``pointer_to_safe_thing - 1000'''' is of a
pointer type, not an integer type. The assignment is illegal; there''s
no implicit conversion from pointers to integers.

Thanks i blindly presumed that for this type it is done;) Now i
checked that
it is not true.

If you make it legal by adding a cast, then you get some arbitrary
integer value; all you know about it is that you ca convert the same
value back to a pointer type and get back the original pointer value.
(Actually for intptr_t that guarantee applies only to void*.)

Now i think that safe way might be something like:

object_t* p = & obj;
object_t* newptr = NULL; /* just for dereferencing */
uintptr_t vp = 0;

vp = (intptr) (void*) p;
vp = vp + INTPTR_MAX * sizeof(*p); /* to overflow + keep alignment */
newptr = (object_t*) (void*) (vp - INTPTR_MAX * sizeof(*p));
assert (newptr == p);

a) If i''d use intptr_t instead, wraparound is not guaranteed (it is
signed value!)?
b) Was this void* cast necessary for transfering values from, to
uintptr_t?
c) Was the way i have used it with stepping by sizeof(*p) correct?
Emulation of stepping a pointer to a type ala
array[5] = array + 5 = (char*) array + 5 * (sizeof(array[0])/
sizeof(char))?


c.***@seznam.cz writes:

Thanks You both much for explanation.

[...]

Now i think that safe way might be something like:

The safe way to do what?

object_t* p = & obj;
object_t* newptr = NULL; /* just for dereferencing */
uintptr_t vp = 0;

You assign values to newptr and vp; why initialize them?

vp = (intptr) (void*) p;

I think you meant:

vp = (uintptr_t)(void*)p;

This obtains a valid uintptr_t value by conversion from a valid
pointer value. So far, so good.

vp = vp + INTPTR_MAX * sizeof(*p); /* to overflow + keep alignment */

You can convert a void* value to uintptr_t. Converting the result
back to void* is guaranteed to give you back the original void* value.
That''s the *only* thing that''s guaranteed. If you modify the
uintptr_t value in any way, converting it back to void* is meaningless
(even if it happens to work on your platform). You can do anything
you like with it *as an integer*, but you''ve lost the association with
any meaningful pointer value.

I can''t figure out what the above statement is supposed to do anyway.
For one thing, you''re mixing intptr_t and uintptr_t values.

newptr = (object_t*) (void*) (vp - INTPTR_MAX * sizeof(*p));

Garbage in, garbage out.

assert (newptr == p);

a) If i''d use intptr_t instead, wraparound is not guaranteed (it is
signed value!)?

Since uintptr_t is an unsigned type, arithmetic on it has wraparound
semantics. Since intptr_t is signed, overflow invokes undefined
behavior. Neither of these is relevant in any portable way to their
relationship to pointers.

b) Was this void* cast necessary for transfering values from, to
uintptr_t?

I think so.

c) Was the way i have used it with stepping by sizeof(*p) correct?
Emulation of stepping a pointer to a type ala
array[5] = array + 5 = (char*) array + 5 * (sizeof(array[0])/
sizeof(char))?

No, though it might happen to work on your platform.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"


这篇关于指针偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆