为什么所有指向结构的指针都必须具有相同的大小?
C 标准规定:
指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。类似地,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针都应具有相同的表示和对齐要求。所有指向联合类型的指针都应具有相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求。
即sizeof(int*)不一定等于sizeof(char*)- 但sizeof(struct A*)一定等于sizeof(struct B*)。
这个要求背后的原理是什么?据我了解,基本类型不同大小背后的基本原理 是支持近/远/巨大指针等用例(编辑:正如评论和接受的答案中指出的那样,这不是基本原理) - 但不是这个相同的原理适用struct于内存中不同位置的 s 吗?
回答
答案很简单:structandunion类型可以声明为不透明类型,即:没有对structorunion细节的实际定义。如果指针的表示根据结构的详细信息而不同,编译器将如何确定用于作为参数、返回值或什至只是从内存中读取或存储它们的不透明指针的表示。
操作不透明指针类型的能力的自然结果是所有此类指针必须具有相同的表示。但是请注意,指向的指针struct和指向的指针union可能具有不同的表示形式,以及指向基本类型的指针,例如char, int, double...
关于指针表示的另一个区别是指向数据的指针和指向函数的指针之间的区别,它们可能具有不同的大小。这种差异在当前架构中更为常见,尽管在操作系统和设备驱动程序空间之外仍然很少见。函数指针的 64 位似乎是一种浪费,因为 4GB 应该足够用于代码空间,但现代架构利用这个额外的空间来存储指针签名,以加强代码抵御恶意攻击。另一个用途是利用忽略某些指针位的硬件(例如:x86_64 忽略前 16 位)来存储类型信息或使用未修改的 NaN 值作为指针。
此外,C 标准中的此注释没有正确解决遗留 16 位代码中的近/远/巨大指针属性,因为所有指针都可能是近、远或巨大的。然而,它涵盖了混合模型代码中代码指针和数据指针之间的区别,并且在某些操作系统上似乎仍然存在。
最后,Posix 要求所有指针具有相同的大小和表示形式,因此混合模型代码应该很快成为历史上的好奇心。
有争议的是,对于不同数据类型表示不同的体系结构如今已经非常罕见,现在是清理标准并删除此选项的时候了。主要反对意见是支持可寻址单元是大字和 8 位字节使用额外信息寻址的体系结构,这使得char *和void *大于常规指针。然而,这样的架构使指针运算变得非常麻烦,而且也非常罕见(我个人从未见过)。
- @CraigEstey:一些 Microchip 处理器。RAM 只有 32k,但 ROM 大于 64k,并且 `const char *` 可以指向 ROM。
- “Posix 任务......应该很快成为历史的好奇心。” POSIX 没有迹象表明在嵌入式领域占据了显着的市场份额,而嵌入式领域占据了绝大多数用 C 编程的设备。
- 3) 我使用了一个不符合标准的编译器,它的 `sizeof(char *)` 是 2 但 `sizeof(const char *)` 是 3。这听起来很烦人。