【问题标题】:Are there any platforms where pointers to different types have different sizes?是否有任何平台指向不同类型的指针具有不同的大小?
【发布时间】:2010-10-29 07:11:08
【问题描述】:

C 标准允许指向不同类型的指针具有不同的大小,例如sizeof(char*) != sizeof(int*) 是允许的。但是,它确实要求如果指针转换为void*,然后再转换回其原始类型,则它必须与原始值进行比较。因此,从逻辑上讲,sizeof(void*) >= sizeof(T*) 适用于所有类型T,对吗?

在当今使用的大多数常见平台(x86、PPC、ARM 和 64 位变体等)上,所有指针的大小都等于本机寄存器大小(4 或 8 字节),而与指向的对象无关类型。是否有任何深奥或嵌入式平台,其中指向不同类型的指针可能具有不同的大小?我特意询问的是 data 指针,尽管我也想知道是否有平台的 function 指针具有不寻常的大小。

我绝对询问 C++ 的指向成员指针和指向成员函数的指针。它们在常见平台上具有不同寻常的大小,甚至可以在一个平台内变化,具体取决于指向类的属性(非多态、单继承、多继承、虚拟继承或不完整类型)。

【问题讨论】:

  • 很好奇,标准的哪个部分允许不同的指针大小?你介意发布那个部分吗
  • Nit-pick:C 中的“本机整数类型”必须是 int,即使在 64 位平台上也很少是 64 位,AFAIK。换句话说,LP64 比 ILP64 更常见。
  • @JaredPar:我不确定它在标准中的什么地方,但是这个页面lysator.liu.se/c/rat/d9.html#4-9-6-1 提到了它,关于 %p fprintf 格式说明符。 @unwind: s/本机整数大小/本机寄存器大小/
  • 我想知道是否有 N 满足以下条件:sizeof(anypointer)
  • 小观察:所有struct X *指针的大小都是一样的。原因是您可以转发声明一个结构,例如struct X;,然后将指向它的指针放在另一个结构中,struct Y { struct X *x; };,编译器仍然可以知道struct Y 需要多少空间,而不知道struct X

标签: c pointers sizeof


【解决方案1】:

Answer from the C FAQ:

Prime 50 系列使用段 07777,空指针偏移量 0,至少对于 PL/I。后来的模型使用段 0,偏移量 0 表示 C 中的空指针,因此需要新的指令,例如 TCNP(测试 C 空指针),显然是对所有现存的写得不好的 C 代码做出错误假设的一种做法。旧的字寻址 Prime 机器也因需要比字指针 (int *) 更大的字节指针 (char *) 而臭名昭著。

Data General 的 Eclipse MV 系列具有三种体系结构支持的指针格式(字、字节和位指针),其中两种由 C 编译器使用:用于 char * 和 void * 的字节指针,以及用于其他所有内容的字指针.由于历史原因,在 32 位 MV 线从 16 位 Nova 线演变而来的过程中,字指针和字节指针在字的不同位置具有偏移、间接和环保护位。将不匹配的指针格式传递给函数会导致保护错误。最终,MV C 编译器添加了许多兼容性选项来尝试处理存在指针类型不匹配错误的代码。

一些 Honeywell-Bull 大型机将位模式 06000 用于(内部)空指针。

CDC Cyber​​ 180 系列有 48 位指针,由环、段和偏移量组成。大多数用户(在环 11 中)的空指针为 0xB00000000000。在旧的 CDC 补码机器上,使用全一位字作为各种数据(包括无效地址)的特殊标志是很常见的。

旧的 HP 3000 系列对字节地址使用与字地址不同的寻址方案;与上面的几台机器一样,它因此对 char * 和 void * 指针使用与其他指针不同的表示。

Symbolic Lisp Machine,一种标记架构,甚至没有传统的数字指针;它使用该对(基本上是一个不存在的句柄)作为 C 空指针。

根据使用的“内存模型”,8086 系列处理器(PC 兼容)可以使用 16 位数据指针和 32 位函数 指针,反之亦然。

一些 64 位的 Cray 机器在 a 的低 48 位中表示 int * 单词; char * 还使用一些高 16 位来表示 一个字内的字节地址。

其他链接:message from Chris Torek 更多详细信息 关于其中一些机器。

【讨论】:

  • @David Cowden 怀疑这个答案是在被接受的 4 个月后写的。由于 OP 要求提供 an 示例并得到它 - 该答案被接受。这篇文章当然更完整,应该得到很高的投票率。也许高度评价的未接受答案值得社区“接受覆盖”?不过,这听起来像是一个“元”问题。
  • @chux 最好只通知提问者对他们问题的回答已经大大超过了接受的答案,让他们重新考虑。最终由提问者决定哪个回答最能回答他们的问题。我只是发表评论以强调我非常非常喜欢这个答案(=
  • @chux 这就是“民粹主义”徽章的用途。 stackoverflow.com/help/badges/62/populist
【解决方案2】:

不是您要问的,但在 16 位 DOS/Windows 时代,您确实有指针和远指针之间的区别,后者是 32 位的。

我可能语法错误...

int *pInt = malloc(sizeof(int));
int far *fpInt = _fmalloc(sizeof(int));

printf("pInt: %d, fpInt: %d\n", sizeof(pInt), sizeof(fpInt));

输出:

pInt:2,fpInt 4

【讨论】:

  • 呸,我完全忘记了近和远指针。我知道他们的存在,但是当我写这个问题时,他们完全忘记了。
  • 16 位 DOS 应该是符合标准的编译器的示例吗?
  • @sellibitze:你是对的 - far 属性不在任何 C 标准中,因此答案中的 sn-p 不是有效的标准 C。因此这可以说不能完全回答问题(这似乎是在询问标准 C)-但恕我直言,这仍然是一个有价值的答案。
【解决方案3】:

因此,从逻辑上讲,sizeof(void*) >= sizeof(T*) 适用于所有类型 T,对吗?

不一定如此,因为 sizeof 是关于存储表示的,并非所有位模式都必须是有效值。我认为您可以编写一个符合sizeof(int*) == 8sizeof(void*) == 4 的实现,但int* 的可能值不超过2^32 个。不知道你为什么想要。

【讨论】:

  • 这取决于你对“逻辑上”的定义;v)
  • 如何使用malloc() 分配,然后分配int*?另外,您的意思是“对于一个 int* 的可能值不超过 2^32 个”还是“对于一个 int”?
  • @smci:我的意思是int*。关键是,如果int* 的合法值不超过2^32,那么无论int* 的大小是多少,或者哪些值是合法的,实现仍然可以实现从int* 到 4 字节 void* 并再次返回。您可以使用malloc 分配然后分配int*,如下所示:int **ppint = malloc(sizeof(*ppint)); *ppint = 0;。但我看不出这与问题或我的答案有什么关系。
  • 但是你说的是sizeof(int*) == 8的案例。我猜你的意思是“8 个字节,但高 4 个字节用零填充”。这不是一般情况sizeof(int*) == 8
  • 对,它可能是填充的高字节。它可能是其他一些字节。使用和未使用值的分布可能非常复杂。正如我所说,我想不出任何充分的理由来实际实施它,但我不是在谈论一般情况,我是在谈论某事是否“合乎逻辑”。一般情况是sizeof(T*) 对于所有对象类型 T 都是相同的。
【解决方案4】:

在 DOS、8088 和分段内存的黄金年代,通常指定一个“内存模型”,例如所有代码都适合 64k(一个段),但数据可以跨越多个段;这意味着一个函数指针是 2 个字节,一个数据指针是 4 个字节。不确定是否有人还在为这种机器编程,也许有些人仍然在嵌入式应用中存活下来。

【讨论】:

  • 它们在嵌入式世界中并不少见。 DOS还是用的很多。
  • @Nils,我最近(在我发布这篇文章之后)采访了一位应届毕业生 (EE),他的主要装配经验(当然来自嵌入式应用)结果证明是使用英特尔 8051 和飞思卡尔 6811——我在 70 年代在大学学习的 CPU 的 8 位后代(!),即便如此,我们还是渴望获得更强大的 CPU,例如 Zilog Z80。所以 8088 和 DOS 将是一个很大的进步......!
【解决方案5】:

人们可以很容易地想象一个哈佛架构的机器具有不同大小的函数指针和所有其他指针。不知道有什么例子...

【讨论】:

  • 2013 年嵌入式处理器 (PIC) 中经常使用的哈佛架构。
  • 是的,哈佛架构出现在很多嵌入式芯片中。但是你知道有一个实现了与同一平台上的其他指针大小不同的函数指针吗?
  • PIC16(CCS 编译器)使用了一个愚蠢的 9-10 位 RAM(1-2 位页面寄存器和 8 位偏移量。)甚至memcpy() 也很麻烦。非易失性数据卡在 ROM 中(我认为 14-16 位偶数地址指向 1 个字节)并使用了特殊的memcpy()/strcpy()。函数很难通过函数指针获取/使用,并且将 14-16 位地址转换为半个 14 位指令字,因此地址必须是偶数。当然我把这个故事搞砸了,因为我更频繁地使用 PIC24 并且让编译器处理地址知道,我,编码器,不能随意混合指针类型。
【解决方案6】:

在一些带有分页闪存或 RAM 的嵌入式微控制器上仍然使用近和远指针,以允许您指向同一页面(近指针)或另一个页面(远指针,因为它包含页面而更大)中的数据信息)。

例如,飞思卡尔的 HCS12 微控制器使用 16 位冯诺依曼架构,这意味着任何地址都不能超过 16 位。由于这会对可用代码空间量造成限制,因此有一个 8 位页面寄存器。

所以要指向同一代码页中的数据,您只需指定 16 位地址;这是一个近点指针。

要指向另一个代码页中的数据,您必须在该页中同时包含 8 位页号和 16 位地址,从而生成 24 位远指针。

【讨论】:

    【解决方案7】:

    例如,指向数据的指针的大小可能不同于指向函数的指针。这在嵌入式系统的微处理器中很常见。像 dmckee 提到的哈佛架构机器使这很容易发生。

    事实证明,它让 gcc 后端开发起来很痛苦! :)

    编辑:我无法详细介绍我正在谈论的特定机器的细节,但让我补充一下为什么哈佛机器让这很容易发生。哈佛架构有不同的存储和指令和数据的路径,因此如果指令总线比数据总线“大”,你一定会有一个函数指针,其大小比指向数据的指针大!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-26
      • 2017-03-26
      • 2019-04-13
      • 2014-04-05
      • 1970-01-01
      相关资源
      最近更新 更多