我刚刚阅读C FAQ on pointers的部分。
它讨论了无法使用void *
指针来保存函数指针,因为指向数据的指针和指向函数的指针在某些平台上可能有不同的大小,void *
只能保证足够大以容纳指针数据。
任何人都可以提供一个平台示例,其中指向数据的指针和指向函数的指针实际上具有不同的大小吗?
答案 0 :(得分:10)
> 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
在“媒介”模型中生成代码
答案 1 :(得分:8)
在实模式x86上,代码&amp;数据由段+偏移量访问,每个都是16位数量。 “近”指针仅为16位且使用当前段,“远”指针为32位并指定段和偏移量。对于C编译器,您可以选择几种不同的内存模型,代码和数据的近端或远端指针的默认值不同。
例如,“中”存储器模型在数据指针附近使用,但默认情况下用于代码的远指针。
如果一些现代嵌入式处理器具有类似的内存模型,我不会感到惊讶。
答案 2 :(得分:6)
请注意,POSIX需要指向对象的指针和指向函数的指针大小相同:
2.12.3指针类型
所有函数指针类型应与void指向的类型指针具有相同的表示形式。将函数指针转换为void *不得改变表示。这种转换产生的void *值可以使用显式转换转换回原始函数指针类型,而不会丢失信息。
注意: ISO C标准不要求这样,但它是POSIX一致性所必需的。
因此,声称符合POSIX标准的系统将是统一的。如果你只针对这样的机器,那么你不必担心这些差异。
答案 3 :(得分:5)
16位PIC单片机(Microchip PIC24和dsPIC)是具有不同数据和代码空间指针大小的哈佛架构器件的示例。单独的地址空间大小不同 - 片上SRAM的芯片面积成本比Flash存储器要小得多,因此数据指针可以更小。
PIC12,PIC16和PIC18架构也是如此,但dsPIC是我目前正在使用的。
答案 4 :(得分:4)
使用Harvard Architecture的计算机具有用于指令和数据的单独存储,并且相应地具有用于指令和数据的单独地址空间。在这样的架构中,没有真正的理由让两个地址空间(或支持它们的物理内存)具有相同的大小。
答案 5 :(得分:1)
这是一种“依赖”的情况。在C ++中我记得成员函数指针实际上是两个指针大小,但这可能纯粹是一个实现细节。
在一些非常古老的预制PC系统中,你可能还有指针大小取决于被引用的内容(但是你也可以有11位字符:D)