指针的大小和体系结构

AKL*_*AKL 17 c c++ assembly portability

通过在普通台式PC上运行简单的C ++程序进行基本测试,似乎可以假设任何类型的指针(包括函数指针)的大小等于目标体系结构位的大小。

例如:在32位体系结构中-> 4个字节,在64位体系结构中-> 8个字节。

但是我记得读过的话,它不是一般的那样!

所以我想知道这种情况会怎样?

  • 为了使指向数据类型的指针的大小与指向其他数据类型的指针的大小相等
  • 为了使指向数据类型的指针的大小与指向函数的指针的大小相等
  • 为了使指向目标体系结构的指针大小相等

Eri*_*hil 17

不,假设是不合理的。进行此假设可能会导致错误。

C或C ++中的指针(和整数类型)的大小最终由C或C ++实现确定。普通的C或C ++实现受其目标体系结构和操作系统的影响很大,但它们可能出于执行速度以外的原因而选择其类型的大小,例如支持较小的内存使用,支持未写入代码的目标。完全可移植到任何类型的大小,或者支持更轻松地使用大整数。

我已经看到了针对64位系统但提供32位指针的编译器,目的是构建使用较小内存的程序。(已经观察到,指针的大小是内存消耗的重要因素,这是由于使用了许多具有许多连接的结构以及使用指针的引用。)在假设指针大小等于64位寄存器的情况下编写的源代码大小会破裂。

  • @Ruslan:不,不是。 (5认同)
  • 您看到的编译器很可能是[x32 ABI](https://en.wikipedia.org/wiki/X32_ABI)的GCC。 (3认同)

klu*_*utt 13

合理地假设,通常任何类型的指针(包括指向函数的指针)的大小等于目标体系结构位

要看。如果您打算快速估计内存消耗,那么可能就足够了。

(包括指向函数的指针)

但这是重要的一句话。尽管大多数指针具有相同的大小,但函数指针可能会有所不同。不保证a void*将能够保存函数指针。至少,这对于C是正确的。我不了解C ++。

所以我想知道这种情况会怎样?

原因可能有很多原因。如果您的程序的正确性取决于此大小,则永远无法做这样的假设。而是检查一下。一点也不难。

您可以使用此宏在C编译时检查此类情况:

#include <assert.h>
static_assert(sizeof(void*) == 4, "Pointers are assumed to be exactly 4 bytes");
Run Code Online (Sandbox Code Playgroud)

编译时,会出现错误消息:

$ gcc main.c 
In file included from main.c:1:
main.c:2:1: error: static assertion failed: "Pointers are assumed to be exactly 4 bytes"
 static_assert(sizeof(void*) == 4, "Pointers are assumed to be exactly 4 bytes");
 ^~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

如果您使用的是C ++,则可以跳过,#include <assert.h>因为它static_assert是C ++中的关键字。(并且您可以_Static_assert在C中使用关键字,但是它看起来很丑陋,因此请使用include和宏。)

由于这两行非常容易包含在您的代码中,因此如果您的程序使用错误的指针大小无法正常工作,则没有任何借口不这样做。


Use*_*ess 9

合理地假设,任何类型的指针(包括指向函数的指针)的大小通常都等于目标体系结构位?

这可能是合理的,但并非可靠地正确。因此,我猜答案是“否,除非您已经知道答案是(并且不担心可移植性)”

潜在地:

  • 系统可以具有不同的寄存器大小,并且使用不同的底层宽度进行数据和寻址:“目标体系结构位”对于这种系统甚至意味着什么都不清楚,因此您必须选择特定的ABI(完成后,您必须选择了解该ABI的答案)。

  • 系统可以支持不同的指针模型,如老的nearfarhuge指针; 在这种情况下,您需要知道代码在哪种模式下编译(然后您知道该模式的答案)

  • 系统可能支持不同的指针大小,例如已经提到的X32 ABI或此处描述的其他任何流行的64位数据模型

最后,这种假设没有明显的好处,因为您可以sizeof(T)直接将其用于T感兴趣的任何事情。

如果要在整数和指针之间转换,请使用intptr_t。如果要将整数和指针存储在同一空间中,请使用union


Mam*_*ita 7

目标架构的“位”表示寄存器的大小。例如 Intel 8051是8位的,并且在8位的寄存器上运行,但是(外部)RAM和(外部)ROM是使用16位值访问的。


Jes*_*uhl 5

为了正确起见,您不能承担任何责任。您必须检查并准备好应对奇怪的情况。

作为一般经验法则,这是一个合理的默认假设

但是,这并非普遍如此。例如,请参阅X32 ABI,它在64位体系结构上使用32位指针来节省一点内存和缓存占用空间。与AArch64上的ILP32 ABI相同。

因此,为了猜测内存的使用情况,您可以使用假设,这通常是正确的。

  • PAE与任何现有C ++实现上的C ++编程都不相关。它不会增加虚拟地址空间的大小,而只会增加物理地址。而且它仅在启用分页时才起作用,因此在假设的独立式C ++程序中,如果禁用了分页功能,则无法解决超过4GB的物理内存。 (2认同)

Mar*_*nau 5

合理地假设,任何类型的指针(包括指向函数的指针)的大小通常都等于目标体系结构位?

如果您查看当前正在生产的所有类型的CPU(包括微控制器),我会说不。

极端的反例是在同一程序中使用两种不同指针大小的体系结构:

x86,16位

在MS-DOS和16位Windows中,“正常”程序同时使用16位和32位指针。

x86,32位分段

只有少数几个鲜为人知的操作系统使用此内存模型。

程序通常同时使用32位和48位指针。

STM8A

这种现代的汽车8位CPU使用16位和24位指针。当然,两者都在同一程序中。

AVR微小系列

使用8位指针寻址RAM,使用16位指针寻址闪存。

(据我所知,AVR tiny无法用C ++编程。)