【问题标题】:Could it be the case that sizeof(T*) != sizeof(const T*)?会不会是 sizeof(T*) != sizeof(const T*)?
【发布时间】:2016-02-25 11:42:31
【问题描述】:

我正在和我的老板争论这件事。他们说“是的,他们可以与众不同。”

sizeof(T*) != sizeof(const T*) 是否可能是 T 类型?

【问题讨论】:

  • 我觉得标题可能是这样,而你的问题中的句子Is it possible有点误导,或者可能与有不匹配语言律师标签。您是否想知道无论标准怎么说,它是否会发生,或者您是否想知道这样的实现是否符合要求?因为有几个答案读起来像以前的那样,我明白他们为什么会这样解释这个问题。

标签: c++ language-lawyer


【解决方案1】:

不,它们不可能不同。对于足够不同的T1T2sizeof(T1 *) 可以不同于sizeof(T2 *),但如果T2 只是const T1,则:

3.9.2 复合类型 [basic.compound]

3 [...] 指向布局兼容类型的 cv-qualified 和 cv-unqualified 版本 (3.9.3) 的指针应具有相同的值表示和对齐要求 (3.11)。 [...]

并且任何类型 T 都与自身布局兼容:

3.9 类型 [basic.types]

11 如果T1T2 两种类型是同一类型,那么T1T2布局兼容 类型。 [...]


值表示与对象表示有关,如果没有相同的对象表示,则不能具有相同的值表示。后者意味着需要相同的位数。

3.9 类型 [basic.types]

4 T 类型对象的 对象表示T 类型对象占用的 Nunsigned char 对象的序列,其中N 等于sizeof(T)。对象的值表示是一组保存T 类型值的位。对于普通可复制类型,值表示是对象表示中的一组位,它们确定 ,它是实现定义的一组值的一个离散元素。44

44) 目的是 C++ 的内存模型与 ISO/IEC 9899 编程语言 C 的内存模型兼容。

要求的重点,它不只是说这两种类型具有相同的对象表示的原因是T *const T * 不仅具有相同的位数,而且它是T *const T * 中构成该值的相同位。这不仅是为了保证sizeof(T *) == sizeof(const T *),而且甚至意味着您可以使用memcpyT * 指针值复制到const T * 指针值,反之亦然,并获得有意义的结果,完全相同你会得到const_cast的结果。

对齐要求也提供了一些额外的保证,但是它们很难正确解释并且与这个问题没有直接关系,并且标准中存在破坏某些预期保证的问题,所以我认为最好忽略它在这里。

【讨论】:

  • 请注意,这只是标准。我已经为嵌入式目标使用了一个实际的编译器,其中T*const T* 的大小不同(RAM 指针和 ROM 指针)。
  • @ElderBug 虽然这绝对是有趣的信息,但该编译器是否声称符合任何标准?
  • @hvd 我认为没有,但区分T*const T* 是一些小型嵌入式目标的正确选择。该标准在这一点上确实存在缺陷,因为它假设可以使用相同的指针访问 RAM 和 ROM。我记得的目标有不同的指令来访问 RAM(短 16 位指针)和 ROM(长 32 位指针),所以试图在它们之间进行转换被编译器拒绝。
  • 在 PIC 情况下,您拥有的是 rom const T*,而不仅仅是 const T*,因此此规则不适用。
  • @ElderBug:请注意,标准要求您可以有一个const T* 到 RAM。因此,如果您需要不同的指令来访问 ROM 和 RAM,则不能假设取消引用 const T* 等于使用 ROM 访问指令。这是 C++ 的基础;否则,数百万个 int Foo::getX const() 方法会中断。
【解决方案2】:

Microchip 发布了这样一个 C 编译器,其中 sizeof(T*) 为 2,而 sizeof(const T*) 为 3。

C 编译器在某些方面不符合标准,所以这并没有说明这是有效的(我怀疑它不是,其他答案也同意)。

【讨论】:

  • 另外,这是一个 C++ 问题
  • 高度怀疑 C 和 C++ 在这里有不同的标准。
【解决方案3】:

嗯,这是非常深奥的,但我认为理论上 可能 有一个架构,例如,地址 0 有 256 字节的 RAM,而地址 0 有几千字节的 ROM更高的地址。 可能有一个编译器会为int *i 创建一个 8 位指针,因为 8 位足以保存高度有限的 RAM 区域中的任何对象的地址,当然任何可变对象都是隐式知道在 RAM 区域中。 const int *i 类型的指针需要 16 位,以便它们可以指向地址空间中的任何位置。 8 位指针 int *i 可转换为 16 位指针 const int *i(但反之亦然),因此可以满足 C 标准的可转换性要求。

但如果存在这样的架构,我肯定希望看到它(但不会为它编写代码):)

【讨论】:

  • @Bathsheba 我强烈怀疑,因为,是的,sizeof(T*) 可以不同于 sizeof(S*),但 int 应该能够保存 [-32767, +32767] 中的所有值,这至少需要 16 位。所以int 不能是 8 位长。
  • @black - 这从未提及 int 本身的大小,只是指向 int 的指针的大小。
  • 首先,这个问题是关于 C++,而不是关于 C。其次,C 具有我在回答中提到的相同要求,即 T *const T * 具有相同的表示形式,并将其表述为:“同样,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。”您假设的实现违反了该要求。
  • 哈佛架构有很多数据和代码空间不同的地方,常量可以存储在只读代码空间中,因此可能有不同的指针大小
  • @hvd,是的,很抱歉打扰了...是的..,我没有写答案来与任何人打架...他问是否可能..(“会不会是这样……”),提出这样的问题会以一种有趣的方式激活大脑……无论如何,我只是认为它可能 i> 可能 .. 与其是否合规无关,只是它可能是可能的,并且这样的编译器实际上在某种程度上是有意义的。而且我认为我可能在几十年前实际上遇到过这样的编译器,对于一些 8051 或其他东西。是的,绝对是 C,而不是 C++。
【解决方案4】:

就标准 C++ 而言,它们没有区别。 C 和 C++ 在这一点上是相似的。

但是有许多架构为它们编写的编译器不遵循此规则。事实上,我们并不是真的在谈论标准 C++,有些人会争辩说该语言不是 C++,但我对您的问题的阅读(在添加语言律师标签之前)更多的是关于这种可能性。

在这种情况下,这是可能的。您可能会发现指向 ROM 的指针(因此为 const)与指向 RAM 的指针(const 或非 const)的大小不同。

如果您确定您的代码只会在标准投诉编译器上结束,那么您的假设是正确的。如果不是,那么我会仔细考虑依赖它们的大小是否相同。

【讨论】:

  • “虽然必须支持从 char*const char* 的隐式转换,但反之则不然。” 对于所有 T 来说都是如此,不是吗?
  • 您能否提供包含sizeof(T*) != sizeof(const T*) 的可编译代码来支持您的回答?
  • @TobiMcNamobi :在满足此要求的环境中编写的 16 位 x86 代码将无穷无尽(即使没有明确展示)。在 Compact、Large 和 Huge 内存模型中,堆栈指针接近(16 位),数据指针接近或巨大(32 位)。编译时常量,例如常量字符串,被存储到数据段中。作为const char *,它们可以存储在16 位中,但也可以存储在任何32 位char 指针中。不能保证反向转换是可能的。
  • "除非明确说明," -- 确实如此。在您发布答案之前,我准确地发布了标准所说的内容。
猜你喜欢
  • 2016-12-12
  • 1970-01-01
  • 1970-01-01
  • 2017-05-20
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2018-03-09
  • 2011-12-17
相关资源
最近更新 更多