如何使用内存寄存器来保存不同的类型



我的印象是,如果一个程序为变量类型整数保留内存(大小为8字节)保留的内存将是8个不同的寄存器,它们依次出现在内存中。

我的问题如下:

  1. 假设答案会有所不同,我上面的陈述是一个很好的概括,即不同类型的变量所需的每个字节等于使用内存中的1个寄存器的变量?(即1字节需要内存中的一个寄存器)

  2. 如果这是真的,每个寄存器在内存中持有多少位?或者如果我买了一台32位的计算机,这是否意味着内存中的每个寄存器都有32位?

  3. 如果整数类型需要8个不同的寄存器为其8字节的大小,每个不同的寄存器中包含什么?

  4. 我也在努力理解类型的概念。我知道如果你有32位你可以表示无符号整数取值范围是0 ~ 4294967295。但是如果我存储了无符号整数CPU如何知道这个内存单元中的二进制表示需要被解码成无符号整数格式吗?也就是说,是为特定类型预留的内存指定了特定类型,还是指针指定了特定类型,或者可能是完全不同的类型?

我对二进制算术、汇编语言、引用、指针以及变量和数组如何在内存堆中存储的概念有一定的了解(所以我将使用这些上下文理解任何答案)。我会用C、c++和Java编程。谢谢你的帮助。

1,2,3:不要将内存称为寄存器;虽然我以前见过这样做,这很令人困惑。64位处理器有8字节宽的寄存器,32位处理器有4字节宽的寄存器,但是当这些寄存器被复制到RAM时,它只是内存中的字节。整数的哪一部分存储在哪个字节中取决于处理器的端序:小端序系统将在0x1中存储8个字节的第一个(最低)地址,而大端序系统将在最后一个地址中存储1位。

4: CPU不知道也不关心;"types"是一个高级语言结构,对于CPU来说,一切都是一个数字:"abcd"是一个数字,0xf0f0f0f0是一个数字。你必须根据你想让它做的事情给它指令,例如,如果你想让它把数字当作有符号的,请使用IDIV而不是DIV。

类型在很大程度上是虚构的,这有利于编程语言。对于处理器来说,位就是位,它们除了在单个指令执行期间的短暂时间外,没有任何意义,当该指令结束时,它们就失去了意义。

Dijkstra:"计算机科学与计算机无关,正如天文学与望远镜无关。">

您需要指定您对您的问题感兴趣的处理器,或者您是否对处理器一般感兴趣。今天常见的处理器组合从8位寄存器到64位或更大的寄存器,包括8位、16位、32位、64位寄存器的处理器。

也不要对寄存器中的一切感到困惑,一些处理器有很多寄存器和高级代码中的许多项目在寄存器中坐了一段时间,而其他处理器没有很多寄存器,大多数变量都在ram中而不是在寄存器中。更常见的是,即使寄存器长时间保存该数据,也会为变量提供一些ram。优化器确实破坏了这种平衡,所以很难做出一般的声明。

你说你懂汇编语言,以这个汇编语言伪代码为例:

mov r1,#0x20000000
shl r2,r0,5
add r1,r2
ldr r0,[r1]

这类似于你可能看到的,如果你有一个32字节的结构体数组,你想获得第一个元素,假设它是一个单精度浮点数。你想从寄存器r0中保存的数组中的元素号中获得浮点数,我们不关心元素号是什么,代码对它进行操作。

struct 
{
float f;
stuff...32 bits total
} mystruct[MYSTRUCTSIZE];
...
unsigned int i;
...
something=mystruct[i].f
...
上面的汇编伪代码计算mystruct[i]。F地址,并将其从内存中加载,以供something代码输入或使用。

我们可能碰巧知道0x20000000位是这个结构体数组所在的内存中的某个地址,但是现在,对于mov指令,它只是位,我们正在加载到寄存器中的即时值。通常mov指令不影响标志,所以它对cpu没有任何有符号或无符号的意义,除了一些进入寄存器的位。假设这个伪代码

有32位寄存器和地址空间如前所述,0保存着结构体数组的索引,所以我们乘以32,左移指令不关心这是一个索引,也不关心5的移位与结构体有关,它只是把位输入到alu中,导致位移到一边,零移到另一边。一些cpu会把最后一个位移到进位,不是作为进位,而是作为级联移位的占位符,同样,如果你认为这是一个双补数(移位后),或者想在编程中有一些捷径,可以计算zflag和n标志(符号位)。但这些对cpu来说只是位,没有意义。

在这一点上,作为人类,我们认为r2在内存中保存了一个偏移量,用于进入结构体数组的索引,但对于cpu来说,它只是位。我们将一个操作数视为地址,另一个操作数视为偏移量,但对cpu来说,它们只是被操作的位。Add通常不关心有符号和无符号,两个互补的美妙之处是你可以将unsigned和signed输入到相同的加法器逻辑中,它通常计算执行标志(无符号溢出)和v标志(有符号溢出)加上z标志,零和n标志负结果,所有这些都是一次性的,如果它们对Add没有任何意义,就像计算结果一样,以防你想用这些标志做什么。在这种情况下,cpu无法知道我们正在计算一个地址。

现在我们将寄存器中的位定义为地址并执行加载操作。但是它们只被cpu认为是那条指令的地址,在那一刻,在那一刻之前的寄存器是一些位,这些位是加法运算的结果。

我们从内存中读取什么?更多位,不是浮点值,只有32位。现在一些cpu可能有直接的方式从内存直接加载到浮点寄存器,一些cpu没有浮点,它都是用通用寄存器合成的。即使是浮点值也可以使用gprs来处理浮点值,例如上面的代码是这样做的:

mystruct[j].f=mystruct[i].f;

如果可以的话,你可能不想烧录fpu寄存器,你可以使用下面我所示的gpr。如果这段代码附近没有实际的浮点运算,它只是位从一个地方移动到另一个地方,没有理由让fpu参与进来。

上面的代码看起来就像这样:

ldr r1,mystruct_base
shl r2,r0,#5
add r2,r2,r1
ldr r0,[r2]
shl r2,r3,#5
add r2,r2,r1
str r0,[r2]

,其中r0是i, r3是j。cpu不知道也不关心比特是什么,只有少数例外。对于LDR和STR来说,r2是指令时间段,被认为是内存中某个东西的地址。除此之外,没有结构、浮点数、有符号或无符号整数。什么都没有。只是位。

是的,通常当有人说32位计算机时,他们指的是32位寄存器。这是一个很好的概括,通常位大小也是内存总线的地址大小,32位意味着理论上你可以寻址32位的内存,4gb字节。这有点模糊,尽管您可能从x86或其他操作系统中了解到。通常,特别是在x86中,你会看到一个64位处理器在32位模式下运行,基本上运行的代码/指令需要32位寄存器而不是64位,在x86中,"寄存器"有不同的方式来访问它们,如8位、16位、32位或63位,所以你可以玩这些游戏。

你问的所有这些问题以及更多的问题都在处理器的汇编语言中得到回答。现在mips很不幸地让你感到困惑,x86也一样,所以要避免这些,选择一些简单的东西,比如msp430或ARM或ARM在拇指模式下先学习。

最新更新