63

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

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

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

4

7 回答 7

48

C常见问题解答

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 * 指针使用与其他指针不同的表示。

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

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

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

附加链接:来自 Chris Torek 的消息,其中包含有关其中一些机器的更多详细信息。

于 2009-10-08T17:07:51.567 回答
31

不是您要问的,但是在 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

于 2009-05-27T14:41:37.793 回答
14

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

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

于 2009-05-27T15:08:46.333 回答
12

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

于 2009-05-27T14:39:17.203 回答
7

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

于 2009-05-27T14:49:50.710 回答
7

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

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

因此,要指向同一代码页中的数据,只需指定 16 位地址即可;这是一个近指针。

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

于 2009-05-27T15:51:09.790 回答
6

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

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

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

于 2010-03-10T12:59:57.157 回答