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


67

我正在和老板争论这个问题。他们说:“可以,他们可以有所不同。”

有可能是sizeof(T*) != sizeof(const T*)一种类型T吗?


3
我觉得标题很可能是这样,您的问题中的句子是否可能与语言律师标签有点误导或不匹配。您是否想知道它是否有可能发生而不论标准说了什么?还是想知道这样的实现是否符合要求?因为有几个答案读起来像以前一样,所以我可以理解为什么他们可能会这样解释问题。
Shafik Yaghmour

Answers:


81

不,他们不能不同。对于T1T2sizeof(T1 *)可以与充分不同sizeof(T2 *),但是如果T2const T1,则:

3.9.2化合物类型[basic.compound]

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

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

3.9类型[basic.types]

11如果两个类型T1T2是相同类型,则T1T2布局兼容类型。[...]


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

3.9类型[basic.types]

4类型的对象的对象表示形式T是类型的对象所占据的N个 unsigned char对象的序列T,其中N等于sizeof(T)。对象的值表示形式是持有type值的位的集合T。对于普通可复制类型,值表示形式是对象表示形式中确定值的一组位,该是实现定义的一组值中的一个离散元素。44

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

需求的要点是,它不只是说这两种类型具有相同的对象表示形式,原因还在于T *,它们const T *不仅具有相同的位数,而且还具有相同的位数T *const T *组成值。这不仅意味着要保证sizeof(T *) == sizeof(const T *),而且意味着即使您可以memcpy用来将T *指针值复制到const T *指针值(反之亦然)并获得有意义的结果,也可以得到与之完全相同的结果const_cast

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


33
请注意,这只是标准。我已经为嵌入式目标的实际编译器工作过,T*并且const T*大小不同(RAM指针和ROM指针)。
ElderBug 2015年

3
@ElderBug虽然那绝对是有趣的信息,但是该编译器是否声称符合任何标准?

4
@hvd我不认为是这样,但是要与众不同T*,这const T*是一些小型嵌入式目标的正确选择。在这一点上,该标准确实存在缺陷,因为它假定可以使用相同的指针访问RAM和ROM。我记得的目标在访问RAM(短16位指针)和ROM(长32位指针)方面有不同的指令,因此编译器拒绝尝试在它们之间进行强制转换。
ElderBug

8
在PIC情况下,那么您拥有的是一个rom const T*,而不仅仅是一个const T*,因此该规则将不适用。
MrZebra

17
@ElderBug:请注意,该标准要求您必须具有const T*RAM。因此,如果您需要不同的指令来访问ROM和RAM,则不能假定const T*使用ROM-access指令取消引用等于。这是C ++的基础。int Foo::getX const()否则,数百万种方法将中断。
MSalters 2015年

8

Microchip发布了这样的C编译器,其中Csizeof(T*)是2但是sizeof(const T*)3。

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


2
另外,这是一个C ++问题
MM

3
非常怀疑C和C ++在这里有不同的标准。
2015年

5

嗯,这是高度神秘主义的,但是我认为从理论上讲,可能存在一种架构,该架构在地址0中具有256字节的RAM,而在更高地址中具有数千KB的ROM。而且有可能是将创建一个8位的指针编译器int *i,因为8位是足以容纳在极为有限的RAM区域的任何对象,当然是隐含已知的RAM区域中的任何可变对象的地址。类型的指针const int *i将需要16位,以便它们可以指向地址空间中的任何位置。8位指针int *i可转换为16位指针const int *i(反之亦然),因此可以满足C标准的可转换性要求。

但是,如果existenseense中有这样的体系结构,我一定会喜欢的(但不要为它编写代码):)


3
@Bathsheba我强烈怀疑,因为是的,sizeof(T*)它可以与[-32767,+32767]中的所有值不同,sizeof(S*)int应该能够容纳所有这些值,至少需要16位。因此int不能为8位长。
edmz 2015年

1
@black-它从不提及int本身的大小,而只是指向int的指针的大小。
TLW

4
首先,这个问题是关于C ++的,而不是关于C的。其次,C具有我在回答中提到的相同要求,T *并且const T *具有相同的表示形式,并将其表达为:“类似地,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。” 您的假设实现违反了该要求。

2
哈佛有很多架构,其中数据和代码空间是不同的,并且常量可以存储在只读代码空间中,因此可能存在不同的指针大小
phuclv 2015年

@hvd,是的,很抱歉给您带来任何烦恼...是的,我没有写答案与任何人打架...他问是否有可能..(“情况是否如此。 ”,然后以类似有趣的方式回答这样的问题……无论如何,我只是认为这可能可能的..与其说它是否合规,不如说是,可能是因为这样的编译器实际上可能在某种意义上是有意义的。而且我认为几十年前我可能实际上遇到过这样的编译器,大约需要8051。是的,绝对是C,而不是C ++。
PkP

2

就标准C ++而言,它们不能有所不同。C和C ++在这一点上是相似的。

但是,有许多体系结构为它们编写了不遵循此规则的编译器。确实,那时我们并不是真正在谈论标准C ++,然后有人认为该语言不是C ++,但是我对您的问题的理解(在添加语言律师标签之前)更多地是关于这种可能性。

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

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


1
“尽管必须支持从char*到的隐式转换const char*,但事实并非如此。” 所有人都是这样T,不是吗?
Baum mit Augen

5
您能否提供包含sizeof(T*) != sizeof(const T*)支持您答案的可编译代码?
TobiMcNamobi

@TobiMcNamobi:在满足此要求的环境中将写入无数的16位x86代码(即使未明确展示)。在Compact,Large和Huge内存模型中,堆栈指针接近(16位),数据指针接近或巨大(32位)。编译时间常量(例如常量字符串)存储在数据段中。作为const char *它们可以存储在16位,但也可以存储在任何32位char的指针。不能保证反向转换是可能的。
埃里克·塔

3
“除非明确说明,”-确实如此。在您发布答案之前,我准确地发布了标准说得好的地方。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.