指向非并集类的指针的大小不同

Can size of pointers to non-union classes differ?

本文关键字:指针      更新时间:2023-10-16

我知道有些硬件平台需要比指向int更多的信息来指向char(该平台具有不可寻址的字节,因此指向char的指针需要存储指向单词的指针以及单词中字节的索引)。因此CCD_ 4在这样的平台上是可能的。

指向非并集类的指针会发生类似的情况吗?C++允许在虚拟函数上使用协变返回类型。假设我们有这样的类:

struct Gadget
{
  // some content
};

struct Widget
{
  virtual Gadget* getGadget();
};

任何调用getGadget()的代码在接收Gadget*时都必须工作,但当接收到指向从Gadget派生的类型的指针(可能是在完全不同的库中定义的类型)时,相同的代码(实际上是相同的编译的二进制代码)也必须工作。我能合理地看到这种情况发生的唯一方法是针对所有非并集类类型TUsizeof(T*) == sizeof(U*)

因此,我的问题是,给定一个特定平台上的一个特定的实用编译器(不包括假设的Hell++),期望所有指向非并集类类型的指针都具有相同的大小是否合理?或者,编译器可能希望使用不同的大小,同时保持与协变返回类型的一致性,这是否有实用的原因?

在存在不同"级别"指针的平台上(如__near__far),假设相同的属性应用于两者。

C有一个硬性要求,即指向所有结构类型的所有指针都具有相同的表示和对齐方式。

6.2.5类型

27[…]指向结构类型的所有指针应具有彼此相同的表示和对齐要求。[…]

C++实际上需要与C实现的二进制兼容性,因为标准对extern "C"的要求,所以间接地,这需要指向在C中有效的结构类型(POD类型,几乎是)的所有指针在C++中也具有相同的表示和对齐。

似乎没有对非POD类型做出这样的要求,因此在这种情况下,允许实现使用不同的指针大小。你建议这是行不通的,但以你的例子,

struct G { };
struct H : G { };
struct W
{
  virtual G* f() { ... }
};
struct X : W
{
  virtual H* f() { ... }
};

可以转换为(伪代码)

struct W
{
  virtual G* f() { ... }
};
struct X : W
{
  override G* f() { ... }
  inline H* __X_f() { return static_cast<H *>(f()); }
};

这仍然符合语言的要求。

指向结构类型的两个指针可能不相同的一个有效原因是,当C++编译器被移植到一个平台上时,该平台上的现有C编译器的ABI设计不佳。G是POD类型,因此G *需要与C中的完全相同。H不是POD类型,所以H *不需要匹配任何C类型。

对于对齐,这实际上是可能发生的:真正发生的事情是,典型的GNU/Linux系统上的x86-32 ABI需要64位整数类型进行32位对齐,尽管处理器的首选对齐方式实际上是64位。现在又来了一个实现者,他们决定确实需要64位对齐,但如果他们想保持与现有实现的兼容,就会陷入困境。

对于尺寸,我想不出一个合理的情况会发生,但我不确定这是否是我缺乏想象力。

据我所知,C和C++假设内存是线性字节可寻址的。然而,某些平台(早期的ARM)坚持使用单词对齐加载和存储。在这种情况下,编译器的责任是将指针舍入到单词边界,然后在获取字符时执行必要的移位操作。

但由于这一切都只在加载和存储时完成,所以所有指针看起来仍然相同。