指针对齐属性 [英] pointer alignment property

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

问题描述

以下是Eric Sosman提到

来自
http://groups.google.com/group/comp....4?dmode=source


任何类型T的对齐要求必须是sizeof(T)的
除数。 (证明:在`T数组[2];''两个

`array [0]''和`array [1]''必须正确对齐。)

由于`sizeof(unsigned char)''只能被一个

整除,并且因为一个是每个类型'的大小的除数,所以每个

类型都适当对齐对于`unsigned char''。"

现在,如果在一个系统中sizeof(long *)== sizeof(int *)

暗示是指向int可以保存任何值

指向long的指针,反之亦然,但是这个
并不一定意味着取消引用指向

int的指针将产生一个有效值或取消引用指向long

将产生一个有效值。例如:


long * p;

int * p1;

long value = LONG_MAX;


p =& value;

p1 = p;


* p1; / *可能是陷阱表示 - 对吗? * /


任何一个都有可能产生一个陷阱

表示给出long和int之间不同的大小或

甚至通过修改int类型对象的填充位

(如果sizeof(long)> = sizeof(int)并且并非所有位都用于

代表值在int)中,如果对于所述对象类型存在这样的填充位,则为



指向对象类型的特殊情况是

指向void的指针,指向char的指针,指向unsigned char的指针,

指向signed char的指针。


这些指针类型正确对齐以保存任何指针

表示对象位置的值。

但是,当解除引用任何指针类型时,您可能不一定期望有效结果

(指向void

除外),因为在c89 / 90下指向char的指针或

指向signed char的指针可以通过解除引用来支持
调用undefined行为?我在这里不太确定。

我知道在c99陷阱表示中引入了

以及实现定义信号的提升。

所以在c99的情况下,很明显后两者可能会发生,例如,如果您要执行以下操作:


sizeof(long * )== sizeof(char *)

sizeof(char)< sizeof(长)


长* p;

char * p1;

长a = 10;


p1 = p =& a;


* p1; / *

*未定义的行为由于:

* a)陷阱表示

* b)实现定义的信号提升

* /

我的解释是否合适?在c89下是什么情况?
在c89下不存在陷阱表示

等概念?


-

aegis

解决方案



aegis写道:

以下是Eric Sosman提到的
http://groups.google.com/group/comp....4?dmode=source

对齐要求任何类型T必须是sizeof(T)的除数。 (证明:在`T array [2];'''
`array [0]''和`array [1]''必须正确对齐。)
自`sizeof(unsigned char) ''只能被一个人整除,因为一个是各种类型'的除数,每个
类型都适合unsigned char。

现在,如果在一个系统中sizeof(long *)== sizeof(int *)
,则暗示指向int的指针可以包含指向long的任何值
,反之亦然,但是这并不一定意味着取消引用一个指向
int的指针将产生一个有效值或取消引用指向long
的指针将产生一个有效值。例如:

long * p;
int * p1;
long value = LONG_MAX;

p =& value;


可以保留任何价值仅在以下意义上:

memcpy(& i,& p1,sizeof(p));


知道sizeof(long *)= = sizeof(int *)不足以保证

类型''long *''的每个值都正确对齐以允许

转换为''int *' 。

实现对于''int''具有比'/ $
''''更严格的对齐要求是完全合法的(尽管不太可能),所以不保证以下声明已定义

行为:

p1 = p;


即使''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''如果这个值是将
转换回''long *'',它将指向''value''。标准说

没有关于哪个内存''p1'指向的内容。因此,

以下声明:

* p1; / *可能是陷阱表示 - 对吗? * /


有未定义的行为。当然,在实践中,到目前为止,最有可能的是b
指向''value''的第一个sizeof(int)字节。

但是,甚至如果它确实指向那个位置,那么你就没有任何保证

来自''value''的哪些位存储在那些字节中,也不存在什么

命令那些位是存储。你也无法保证

标准的顺序存储''int''的位。如签名

类型,''int''和''long''允许填充位,并且

标准不保证这些填充的位置

位。简而言之,标准

关于评估* p1的结果没有任何用处。

指向对象类型的特殊情况是
指向void,指向char的指针,指向unsigned char的指针,
指向signed char的指针。

这些指针类型被正确对齐以保存任何指向对象位置的指针
值。
但是,在解除引用任何指针类型(指向void
的指针)时,你可能不一定期望有效的结果,因为在c89 / 90下指向char或
的指针指向signed char的指针可以通过解除引用来调用未定义的行为吗?




您可以保证能够访问对象的字节作为

无符号字符数组(6.2.6.1p4) - 标准给出了memcpy()作为复制它的一种方法的例子,但没有指明这是

唯一的方式。由于memcpy()被定义为访问内存,因此它将
复制为unsigned char数组,直接以数组形式访问对象

char也必须正常工作。 />

6.2.6.1p5允许未定义的行为,因为对象有一个陷阱

表示只有当使用的左值没有字符时

类型。


ku **** @ wizard.net 写道:

....

memcpy(& i,& p1,sizeof(p));




更正:


memcpy(& p,& p1,sizeof(p));

< br>


ku****@wizard.net 写道:

aegis写道:

以下是Eric Sosman提到的
http://groups.google.com/group/comp....4?dmode=source

任何类型T的对齐要求必须是sizeof(T)的除数。 (证明:在`T array [2];'''
`array [0]''和`array [1]''必须正确对齐。)
自`sizeof(unsigned char) ''只能被一个人整除,因为一个是各种类型'的除数,每个
类型都适合unsigned char。

现在,如果在一个系统中sizeof(long *)== sizeof(int *)
,则暗示指向int的指针可以包含指向long的任何值
,反之亦然,但是这并不一定意味着取消引用一个指向
int的指针将产生一个有效值或取消引用指向long
的指针将产生一个有效值。例如:

long * p;
int * p1;
long value = LONG_MAX;

p =& value;
它可以保留任何值仅在以下意义上:
memcpy(& i,& p1,sizeof(p));

知道sizeof(long *)== sizeof(int *)不是足以保证long *类型的每个值都正确对齐以允许
转换为int *。
实现对''int'的严格对齐要求比对''long'的
更完全合法(尽管不太可能),因此没有保证以下声明已定义
行为:

p1 = p;



即使''p''正确对齐,唯一的事情标准
保证'p1'的价值是,如果这个值被转换回''long *'',它将指向''value''。该标准没有说明p1指向哪一段记忆。因此,
以下声明:




如果您要将p1的值转换回p并生成

原始值,那么这意味着指针对象必须足够宽以容纳任何指针对象类型的指针值,是吗?


那么唯一的问题就是尊重对齐,是否是或者
不是指向的对象类型共享相同的对齐

要求。因此,如果int和long确实共享相同的对齐

要求,那么上面的p1解引用是合法的吗?

* p1; / *可能是陷阱表示 - 对吗? * /



有未定义的行为。当然,在实践中,到目前为止,最有可能的是它指向''值'的第一个sizeof(int)字节。
然而,即使它确实指向该位置,你没有任何保证
来自''value''的哪些位存储在这些字节中,也不存储这些位的存储顺序。您也无法保证
标准的顺序存储int的位。作为已签名的
类型,允许''int''和''long''有填充位,
标准也不保证这些填充位的位置。简而言之,标准
关于评估* p1的结果没有任何用处。

指向对象类型的特殊情况是
指向void,指向char的指针,指向unsigned char的指针,
指向signed char的指针。

这些指针类型被正确对齐以保存任何指向对象位置的指针
值。
但是,在解除引用任何指针类型(指向void
的指针)时,你可能不一定期望有效的结果,因为在c89 / 90下指向char或
的指针指向已签名的char的指针可以通过解除引用来调用未定义的行为吗?



您将被保证能够以对象的形式访问对象的字节
无符号字符数组(6.2.6.1p4) - 标准给出了memcpy()作为复制它的一种方法的例子,但并没有指明这是唯一的方法。由于memcpy()被定义为访问内存,因此它将作为unsigned char数组复制,直接访问对象作为数组的char也必须有效。

6.2。 6.1p5允许未定义的行为,因为只有当使用的左值没有字符
类型时,对象才具有陷阱表示。




但是我很好奇c89 / 90的作用。我想陷阱代表

是在c99中引入的?


-

aegis


The following was mentioned by Eric Sosman
from
http://groups.google.com/group/comp....4?dmode=source

"The alignment requirement for any type T must be a
divisor of sizeof(T). (Proof: In `T array[2];'' both
`array[0]'' and `array[1]'' must be correctly aligned.)
Since `sizeof(unsigned char)'' is divisible only by one
and since one is a divisor of every type''s size, every
type is suitably aligned for `unsigned char''."
Now if on a system where sizeof(long *) == sizeof(int *)
the implication is that a pointer to int can hold any values
that a pointer to long can and vice versa, however this
does not necessarily mean dereferencing a pointer to
int will yield a valid value or dereferencing a pointer to long
will yield a valid value. Example:

long *p;
int *p1;
long value = LONG_MAX;

p = &value;
p1 = p;

*p1; /* possibly a trap representation -- correct? */

It is possible, for either, to yield a trap
representation given disparate sizes between long and int or
even through modifying the padding bits of an object of type int
(if sizeof (long) >= sizeof(int) and not all bits were used to
represent values in an int),
if such padding bits existed for said object type.

And the special case for pointer to object types is
pointer to void, pointer to char, pointer to unsigned char,
pointer to signed char.

These pointer types are correctly aligned to hold any pointer
value that represents the location of an object.
However, you may not necessarily expect valid results
when dereferencing any of those pointer types(pointer to void
excluded), because under c89/90 a pointer to char or
pointer to signed char can, through dereferencing,
invoke undefined behavior? I am not too sure here.
I know under c99 trap representations were introduced
along with the raising of an implementation defined signal.
So in the case of c99, it is clear that the latter two can
happen if you were to, say, do the following:

sizeof(long *) == sizeof(char *)
sizeof(char) < sizeof(long)

long *p;
char *p1;
long a = 10;

p1 = p = &a;

*p1; /*
* undefined behavior due to:
* a) trap representation
* b) implementation defined signal raised
*/
Is my explanation apt? What is the case under c89
being that concepts such as trap representation
do not exist under c89?

--
aegis

解决方案


aegis wrote:

The following was mentioned by Eric Sosman
from
http://groups.google.com/group/comp....4?dmode=source

"The alignment requirement for any type T must be a
divisor of sizeof(T). (Proof: In `T array[2];'' both
`array[0]'' and `array[1]'' must be correctly aligned.)
Since `sizeof(unsigned char)'' is divisible only by one
and since one is a divisor of every type''s size, every
type is suitably aligned for `unsigned char''."
Now if on a system where sizeof(long *) == sizeof(int *)
the implication is that a pointer to int can hold any values
that a pointer to long can and vice versa, however this
does not necessarily mean dereferencing a pointer to
int will yield a valid value or dereferencing a pointer to long
will yield a valid value. Example:

long *p;
int *p1;
long value = LONG_MAX;

p = &value;
It "can hold any values" only in the following sense:
memcpy(&i, &p1, sizeof(p));

Knowing that sizeof(long*)==sizeof(int*) is NOT sufficient to guarantee
that every value of type ''long*'' is correctly aligned to allow
conversion to ''int*''. It''s perfectly legal (though unlikely) for an
implementation to have stricter alignment requirements for ''int'' than
for ''long'', so there''s no gurantee that following statement has defined
behavior:
p1 = p;
Even if ''p'' is correctly aligned, the ONLY thing that the standard
guarantees for you about the value of ''p1'' is that if this value is
converted back to ''long*'', it will point at ''value''. The standard says
nothing about which piece of memory ''p1'' points at. Therefore, the
following statement:
*p1; /* possibly a trap representation -- correct? */
has undefined behavior. Of course, in practice, by far the most likely
thing is that it points at the first sizeof(int) bytes of ''value''.
However, even if it does point at that location, you have no gurantees
about which bits from ''value'' are stored in those bytes, nor in what
order those bits are stored. You also have no guarantees from the
standard which order the bits of an ''int'' are stored in. As signed
types, both ''int'' and ''long'' are allowed to have padding bits, and the
standard provides no guarantees about the location of those padding
bits, either. In short, nothing useful is guaranteed by the standard
about the results of evaluating *p1.
And the special case for pointer to object types is
pointer to void, pointer to char, pointer to unsigned char,
pointer to signed char.

These pointer types are correctly aligned to hold any pointer
value that represents the location of an object.
However, you may not necessarily expect valid results
when dereferencing any of those pointer types(pointer to void
excluded), because under c89/90 a pointer to char or
pointer to signed char can, through dereferencing,
invoke undefined behavior?



You''re guranteed to be able to access the bytes of an object as an
array of unsigned char (6.2.6.1p4) - the standard gives memcpy() as an
example of one way of copying it, but doesn''t specify that this is the
only way. Since memcpy() is defined as accessing the memory it copies
as an array of unsigned char, directly accessing the object as an array
of char must also work.

6.2.6.1p5 allows undefined behavior due to the object having a trap
representation only when the lvalue being used does not have character
type.


ku****@wizard.net wrote:
....

memcpy(&i, &p1, sizeof(p));



Correction:

memcpy(&p, &p1, sizeof(p));



ku****@wizard.net wrote:

aegis wrote:

The following was mentioned by Eric Sosman
from
http://groups.google.com/group/comp....4?dmode=source

"The alignment requirement for any type T must be a
divisor of sizeof(T). (Proof: In `T array[2];'' both
`array[0]'' and `array[1]'' must be correctly aligned.)
Since `sizeof(unsigned char)'' is divisible only by one
and since one is a divisor of every type''s size, every
type is suitably aligned for `unsigned char''."
Now if on a system where sizeof(long *) == sizeof(int *)
the implication is that a pointer to int can hold any values
that a pointer to long can and vice versa, however this
does not necessarily mean dereferencing a pointer to
int will yield a valid value or dereferencing a pointer to long
will yield a valid value. Example:

long *p;
int *p1;
long value = LONG_MAX;

p = &value;
It "can hold any values" only in the following sense:
memcpy(&i, &p1, sizeof(p));

Knowing that sizeof(long*)==sizeof(int*) is NOT sufficient to guarantee
that every value of type ''long*'' is correctly aligned to allow
conversion to ''int*''. It''s perfectly legal (though unlikely) for an
implementation to have stricter alignment requirements for ''int'' than
for ''long'', so there''s no gurantee that following statement has defined
behavior:

p1 = p;



Even if ''p'' is correctly aligned, the ONLY thing that the standard
guarantees for you about the value of ''p1'' is that if this value is
converted back to ''long*'', it will point at ''value''. The standard says
nothing about which piece of memory ''p1'' points at. Therefore, the
following statement:



If you were to convert the value of p1 back to p and produce
the original value, then this implies that pointer objects must
be wide enough to hold pointer values of any pointer object type, yes?

Then the only issue with respect to alignment, is whether or
not the object types pointed at share the same alignment
requirements. So if int and long did share the same alignment
requirements, then the above dereference of p1, would be legal?

*p1; /* possibly a trap representation -- correct? */



has undefined behavior. Of course, in practice, by far the most likely
thing is that it points at the first sizeof(int) bytes of ''value''.
However, even if it does point at that location, you have no gurantees
about which bits from ''value'' are stored in those bytes, nor in what
order those bits are stored. You also have no guarantees from the
standard which order the bits of an ''int'' are stored in. As signed
types, both ''int'' and ''long'' are allowed to have padding bits, and the
standard provides no guarantees about the location of those padding
bits, either. In short, nothing useful is guaranteed by the standard
about the results of evaluating *p1.

And the special case for pointer to object types is
pointer to void, pointer to char, pointer to unsigned char,
pointer to signed char.

These pointer types are correctly aligned to hold any pointer
value that represents the location of an object.
However, you may not necessarily expect valid results
when dereferencing any of those pointer types(pointer to void
excluded), because under c89/90 a pointer to char or
pointer to signed char can, through dereferencing,
invoke undefined behavior?



You''re guranteed to be able to access the bytes of an object as an
array of unsigned char (6.2.6.1p4) - the standard gives memcpy() as an
example of one way of copying it, but doesn''t specify that this is the
only way. Since memcpy() is defined as accessing the memory it copies
as an array of unsigned char, directly accessing the object as an array
of char must also work.

6.2.6.1p5 allows undefined behavior due to the object having a trap
representation only when the lvalue being used does not have character
type.



But I was curious about what c89/90 does. I thought trap representation
was introduced in c99?

--
aegis


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

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