【问题标题】:Can the size of pointers vary between data and function pointers?指针的大小可以在数据和函数指针之间变化吗?
【发布时间】:2010-12-01 05:31:16
【问题描述】:

我只是在阅读C FAQ on pointers 的部分。

它讨论了不能使用 void * 指针来保存函数指针,因为指向数据的指针和指向函数的指针在某些平台上可能具有不同的大小,并且仅保证 void * 大到足以容纳指向数据的指针。

谁能举一个平台的例子,其中指向数据的指针和指向函数的指针实际上具有不同的大小?

【问题讨论】:

标签: c pointers


【解决方案1】:
> type ppp.c
#include <stdio.h>
#include <stdlib.h>

int global = 0;

int main(void) {
    int local = 0;
    static int staticint = 0;
    int *mall;
    int (*fx)(void);

    fx = main;
    mall = malloc(42); /* assume it worked */
    printf("#sizeof pointer to local: %d\n", (int)sizeof &local);
    printf("#sizeof pointer to static: %d\n", (int)sizeof &staticint);
    printf("#sizeof pointer to malloc'd: %d\n", (int)sizeof mall);
    printf("#sizeof pointer to global: %d\n", (int)sizeof &global);
    printf("#sizeof pointer to main(): %d\n", (int)sizeof fx);
    free(mall);
    return 0;
}
> tcc -mc ppp.c
Turbo C  Version 2.01 ...
warnings about unused variables elided ...
Turbo Link  Version 2.0 ...
> ppp
#sizeof pointer to local: 4
#sizeof pointer to static: 4
#sizeof pointer to malloc'd: 4
#sizeof pointer to global: 4
#sizeof pointer to main(): 2
> tcc -mm ppp.c
> ppp
#sizeof pointer to local: 2
#sizeof pointer to static: 2
#sizeof pointer to malloc'd: 2
#sizeof pointer to global: 2
#sizeof pointer to main(): 4

tcc -mc 在“紧凑”模型中生成代码; tcc -mm 在“中等”模型中生成代码

【讨论】:

  • 我假设这是在 X86 机器上?
  • 我认为是 X86 ...我不确定。我在 x86-64 Linux 主机上的虚拟机中运行 DOS。
  • “Turbo C 版本 2.01”是赠品。大约 1989 年的古董编译器。
  • exe 文件的日期为 1989-11-05 02:01am -- 这是一个很棒的编译器!
【解决方案2】:

在实模式 x86 上,代码和数据通过段 + 偏移量访问,每个 16 位数量。 “Near”指针只有 16 位并使用当前段,“Far”指针是 32 位并指定段和偏移量。对于 C 编译器,有几种不同的内存模型可供您选择,代码和数据的近或远指针有不同的默认值。

例如,“Medium”内存模型默认使用近端指针存储数据,而使用远端指针存储代码。

如果某些现代嵌入式处理器具有类似的内存模型,我不会感到惊讶。

【讨论】:

  • 旧的 DOS 和早期的 Windows 环境都是这样,有一些编译器。
  • @Pavel - 问题直接与函数指针和数据指针有关,而不是不同数据类型之间。
【解决方案3】:

16 位 PIC 微控制器(Microchip PIC24 和 dsPIC)是具有不同数据和代码空间指针大小的哈佛架构器件的示例。单独的地址空间大小不同 - 片上 SRAM 的芯片面积成本比 Flash 存储器大,它的面积要小得多,因此数据指针可以更小。

PIC12、PIC16 和 PIC18 架构也是如此,但我目前使用的是 dsPIC。

【讨论】:

    【解决方案4】:

    请注意,POSIX 要求指向对象的指针和指向函数的指针大小相同:

    2.12.3 指针类型

    所有函数指针类型都应与指向 void 的类型指针具有相同的表示。将函数指针转换为 void * 不应改变表示。这种转换产生的 void * 值可以使用显式强制转换转换回原始函数指针类型,而不会丢失信息。

    注意: ISO C 标准不要求这样做,但符合 POSIX 要求。

    因此,声称符合 POSIX 的系统将是统一的。如果您只针对此类机器,则不必担心差异。

    【讨论】:

    • 注意:截至 2013 年 3 月 7 日,POSIX Data types 中似乎缺少此部分,但在 Rationale 中仍然提到它。我已要求 OpenGroup 澄清这是网站的故障还是 POSIX 2013 与 POSIX 2008 相比的实质性变化。我不知道什么时候会收到答复。
    • 您收到回复了吗?
    • @Mitch:是的,我在 2014 年 3 月收到了回复。基本上,这是一个故意的更改,是对错误报告的回复。有关它的讨论可在austingroupbugs.net/view.php?id=74 获得,其中引用的段落被删除并描述了dlsym() 的修订措辞。有时,我需要正确地写下来——我已经打算这样做一年的大部分时间了(而且轮训课从来没有出现过)。
    【解决方案5】:

    使用Harvard Architecture 的机器具有单独的指令和数据存储空间,相应地,指令和数据具有单独的地址空间。在这样的架构中,没有真正的理由让两个地址空间(或支持它们的物理内存)大小相同。

    【讨论】:

    • 最好澄清为什么会这样,而不是仅仅链接到维基百科。
    • 还不错;我认为维基百科的文字信息量很大,并且认为它本身就足够清楚,但理性的人可能会有所不同。
    • 虽然这对于 OP 来说是一个很好的指针 (HA!),但哈佛架构不需要指针大小的差异,但地址空间的大小却需要。您可以在单个地址空间中嵌入 2 个单独的物理内存,在这种情况下,您可能不需要区分 void *s 的大小和其他指针的大小。但我同意哈佛架构机器可能是开始寻找具有单独数据和函数指针的机器的地方。
    • 哦,当然不要求它们有不同的指针大小,它只是让它更有可能,并解释了为什么你可能期望一个标准来支持这些东西.我见过的唯一实际例子是 [修改] 哈佛架构。
    【解决方案6】:

    这是一个“取决于”的情况。在 C++ 中,我记得成员函数指针实际上是两个大小的指针,但这可能纯粹是一个实现细节。

    在一些非常古老的 PC 之前的系统中,您还可以根据所引用的内容设置指针大小(但您也可以使用 11 位字符 :D)

    【讨论】:

    • 在 C++ 中用少于 2 个机器字实现成员函数指针几乎是不可能的;原因是 1)通过成员指针调度必须是虚拟的,所以你不能只存储方法的地址和 2)声明指向前向声明的类的成员指针是合法的,所以你不知道该类是否预先有任何虚方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2016-03-20
    • 2011-12-13
    • 2015-09-10
    • 1970-01-01
    相关资源
    最近更新 更多