是否有任何平台指向不同类型的指针有不同的大小?

Ada*_*eld 57 c pointers sizeof

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

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

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

Rob*_*nes 46

答案来自C FAQ:

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

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

一些霍尼韦尔 - 布尔大型机使用位模式06000作为(内部)空指针.

CDC Cyber​​ 180系列具有48位指针,包括环,段和偏移.大多数用户(在环11中)具有0xB00000000000的空指针.在旧的CDC补充机器上,通常使用全1位字作为各种数据的特殊标志,包括无效地址.

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

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

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

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

其他链接:来自Chris Torek消息,其中包含有关这些机器的更多详细信息.


Ari*_*yck 28

不是你要问的,但是在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));
Run Code Online (Sandbox Code Playgroud)

输出:

pInt:2,fpInt 4

  • 呸,我完全忘记了远近指针.我知道他们的存在,但当我写这个问题时,他们完全放下了我的想法. (4认同)
  • 16位DOS应该是标准符合编译器的一个例子吗? (4认同)
  • @sellibitze:你是对的 - `far` 属性不在任何 C 标准中,所以答案中的片段不是有效的标准 C。因此这可以说并不能完全回答这个问题(这似乎是在询问标准 C) -但恕我直言,这仍然是一个有价值的答案。 (2认同)

Ste*_*sop 13

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

这不一定遵循,因为sizeof是关于存储表示,并且并非所有位模式都必须是有效值.我想,在这里你可以写一个一致实现sizeof(int*) == 8,sizeof(void*) == 4但也有不超过2 ^ 32个可能的值,一个int*.不知道为什么你想要.

  • 这取决于你对"逻辑"的定义; v) (7认同)

Ale*_*lli 11

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


dmc*_*kee 7

可以很容易地想象哈佛架构机器具有不同大小的功能指针和所有其他指针.不知道一个例子......

  • PIC16(CCS编译器)使用了一个高达9-10位的RAM(1-2位页面寄存器和8位偏移量.)甚至是`memcpy()`也很麻烦.非易失性数据卡在ROM中(我认为14-16位偶数地址指向1个字节)并使用了特殊的`memcpy()/ strcpy()`.函数很难通过函数指针获取/使用,也有14-16位地址到半个14位指令字,因此地址必须是偶数.当然我已经把这个故事搞砸了,因为我经常使用PIC24并让编译器处理地址知道,我,编码器,不能狡猾地混合指针类型. (2认同)

Ste*_*off 7

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

例如,飞思卡尔的HCS12微控制器采用16位冯·诺依曼架构,这意味着没有地址可以超过16位.由于这会限制可用的代码空间量,因此存在一个8位页面寄存器.

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

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


Pau*_*tos 6

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

事实证明,这使得gcc后端成为一种痛苦!:)

编辑:我不能详细介绍我正在谈论的具体机器,但让我补充一下为什么哈佛机器让这很容易发生.哈佛架构具有不同的存储和通向指令和数据的路径,因此如果指令的总线比数据的总线"大",则必然会有一个函数指针,其大小大于指向数据的指针!