指向不同类型的指针可以有不同的二进制表示吗?
Can pointers to different types have different binary representations?
我想知道是否允许 C++ 实现以不同方式表示指向不同类型的指针。例如,如果我们有 4 个字节的 sized/aligned int
和 8 个字节的 sized/aligned long
,是否可以表示指向 int
/ 的指针long
因为对象地址分别右移了 2/3 位?这将有效地禁止将指向 long
的指针转换为指向 int
.
的指针
我问是因为 [expr.reinterpret.cast/7]:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v
of object pointer type is converted to the object pointer type “pointer to cv T
”, the result is static_cast<cv T*>(static_cast<cv void*>(v))
.
[Note 7: Converting a pointer of type “pointer to T1
” that points to an object of type T1
to the type “pointer to T2
” (where T2
is an object type and the alignment requirements of T2
are no stricter than those of T1
) and back to its original type yields the original pointer value. — end note]
第一句暗示我们可以将指针转换为任意两种对象类型。但是,(非规范性)Note 7 中的同理心文本表示对齐在这里也起到了一些作用。 (这就是我想出上面那个 int
-long
例子的原因。)
是的
作为具体示例,有一个 C++ 实现,其中指向单字节元素的指针大于指向多字节元素的指针,因为硬件使用字(而不是字节)寻址。为了模拟字节指针,C++ 使用硬件指针加上额外的字节偏移量。
void*
存储额外的偏移量,但 int*
不存储。将 int*
转换为 char*
是可行的(因为它必须符合标准),但是 char*
到 int*
会丢失该偏移量(您的注释隐式允许)。
The Cray T90 supercomputer 是此类硬件的一个示例。
我会看看我是否能找到标准论证,为什么这对兼容的 C++ 编译器来说是有效的;我只知道有人这样做了,不知道这样做是合法的,但该注释暗示它是合法的。
规则将在 to-from void 指针转换规则中。你引用的那段话隐含转发了转换的意思到那里。
7.6.1.9 静态投射 [expr.static.cast]
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.
If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified.
Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b.
Otherwise, the pointer value is unchanged by the conversion.
这表明转换为更对齐的类型会生成一个未指定的指针,但转换为实际上不存在的等于或更少对齐的类型不会更改指针值。
允许从指向 4 字节对齐数据的指针转换为指向 8 字节对齐数据的指针导致垃圾。
然而,每个对象无关的指针转换都需要在逻辑上往返于 void*
。
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v))
.
(来自OP)
涵盖void*
到T*
;我还没有找到 T*
到 void*
的转换文本以使其成为完整的 language-lawyer 级别的答案。
答案是肯定的。仅仅因为标准不禁止它,实现可以决定对指向不同类型的指针使用不同的表示,甚至对同一指针使用不同的可能表示。
由于大多数体系结构现在使用平面寻址(意味着指针的表示只是地址),没有充分的理由这样做。但我仍然记得 8086 系统的旧 segment:offset 地址表示,它曾经允许 16 位系统处理 20 位地址 (1024k)。它使用了一个 16 位的段地址(移动 4 位得到一个真正的地址),以及 far 指针的 16 位偏移量,或者只有 16 位(相对于当前段) 附近 个地址。在这种模式下,远指针有一堆可能的表示。顺便说一句,在大型和紧凑模式 (ref).
中,远寻址是默认设置(因此 normal 源产生了什么)
我想知道是否允许 C++ 实现以不同方式表示指向不同类型的指针。例如,如果我们有 4 个字节的 sized/aligned int
和 8 个字节的 sized/aligned long
,是否可以表示指向 int
/ 的指针long
因为对象地址分别右移了 2/3 位?这将有效地禁止将指向 long
的指针转换为指向 int
.
我问是因为 [expr.reinterpret.cast/7]:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
v
of object pointer type is converted to the object pointer type “pointer to cvT
”, the result isstatic_cast<cv T*>(static_cast<cv void*>(v))
.[Note 7: Converting a pointer of type “pointer to
T1
” that points to an object of typeT1
to the type “pointer toT2
” (whereT2
is an object type and the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. — end note]
第一句暗示我们可以将指针转换为任意两种对象类型。但是,(非规范性)Note 7 中的同理心文本表示对齐在这里也起到了一些作用。 (这就是我想出上面那个 int
-long
例子的原因。)
是的
作为具体示例,有一个 C++ 实现,其中指向单字节元素的指针大于指向多字节元素的指针,因为硬件使用字(而不是字节)寻址。为了模拟字节指针,C++ 使用硬件指针加上额外的字节偏移量。
void*
存储额外的偏移量,但 int*
不存储。将 int*
转换为 char*
是可行的(因为它必须符合标准),但是 char*
到 int*
会丢失该偏移量(您的注释隐式允许)。
The Cray T90 supercomputer 是此类硬件的一个示例。
我会看看我是否能找到标准论证,为什么这对兼容的 C++ 编译器来说是有效的;我只知道有人这样做了,不知道这样做是合法的,但该注释暗示它是合法的。
规则将在 to-from void 指针转换规则中。你引用的那段话隐含转发了转换的意思到那里。
7.6.1.9 静态投射 [expr.static.cast]
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion.
这表明转换为更对齐的类型会生成一个未指定的指针,但转换为实际上不存在的等于或更少对齐的类型不会更改指针值。
允许从指向 4 字节对齐数据的指针转换为指向 8 字节对齐数据的指针导致垃圾。
然而,每个对象无关的指针转换都需要在逻辑上往返于 void*
。
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is
static_cast<cv T*>(static_cast<cv void*>(v))
.
(来自OP)
涵盖void*
到T*
;我还没有找到 T*
到 void*
的转换文本以使其成为完整的 language-lawyer 级别的答案。
答案是肯定的。仅仅因为标准不禁止它,实现可以决定对指向不同类型的指针使用不同的表示,甚至对同一指针使用不同的可能表示。
由于大多数体系结构现在使用平面寻址(意味着指针的表示只是地址),没有充分的理由这样做。但我仍然记得 8086 系统的旧 segment:offset 地址表示,它曾经允许 16 位系统处理 20 位地址 (1024k)。它使用了一个 16 位的段地址(移动 4 位得到一个真正的地址),以及 far 指针的 16 位偏移量,或者只有 16 位(相对于当前段) 附近 个地址。在这种模式下,远指针有一堆可能的表示。顺便说一句,在大型和紧凑模式 (ref).
中,远寻址是默认设置(因此 normal 源产生了什么)