我听说在x86处理器中,字节以'little-endian'字节顺序存储在内存中。意味着首先存储最低有效字节。
我无法理解这个想法及其与字节存储在RAM中的关系。
例如,
#include <stdio.h>
char string[6];
scanf("%5s",string);
在上面的代码中,如果我输入单词“Hello”,则首先存储“o”。(?)
根据我的理解,在C(以及编程通用?)中声明变量时,变量存储在RAM的“堆栈”部分中。所以单词“Hello”会像这样存储在堆栈中:
o <Lower memory addresses>
l
l
e
H <Higher memory addresses>
堆栈从较高的内存地址向较低的内存地址增长,处理器开始从堆栈顶部的第一个字节开始读取字节(较低的内存地址)。
现在,如果我打印字符串的值,我会看到“olleH”。但显然它会打印“Hello”。 这是因为little-endian字节顺序吗?
答案 0 :(得分:7)
为简单起见,让我们讨论一台机器,其中内存中的每个字节都有一个地址。 (有些机器的内存只被组织成具有多个字节的字,而不是单个字节。)在这台机器中,内存就像一个大数组,因此我们可以编写memory[37]
来讨论地址37处的字节。 / p>
要存储字符,我们只需按顺序将它们放在连续的存储位置。例如,要从地址100开始存储字符“Hello”,我们将H置于memory[100]
,e位于memory[101]
,l位于memory[102]
,l位于memory[103]
,并且o memory[104]
。在某些语言中,我们还在memory[105]
处设置零值以标记字符串的结尾。
这里没有端点问题。字符是有序的。
考虑一个像5678这样的整数。这个整数不适合一个8位字节。在二进制文件中,它是1011000101110.这需要至少两个字节来存储,一个字节包含1011,一个字节包含000101110。
当我们将它存储在从位置100开始的存储器中时,我们首先放入哪个字节?这是endian问题。有些机器将高值字节(1011)放在memory[100]
中,将低值字节(000101110)放在memory[101]
中。其他机器以其他顺序执行。高值字节是数字的“大端”,低值字节是“小端”,导致术语“字节序”。(The term actually comes from Jonathan Swift’s Gulliver’s Travels.)
(此示例仅使用两个字节。整数也可以使用四个字节或更多。)
只要有一个由较小对象构成的对象,就会出现endian问题。这就是为什么单个字符不是问题 - 每个字符都进入一个字节。 (虽然,没有物理原因你不能在内存中以相反的顺序存储字符串。我们不这样做。)当一个对象有两个或更多字节时,这是一个问题。您只需选择将字节放入内存的顺序。
堆栈的常见实现从高地址开始,并在向堆栈添加内容时“向下”增长。没有特别的理由这样做;我们也可以让堆栈以其他方式工作。事物就是历史发展的方式。
堆栈增长主要发生在块中。调用函数时,它会向堆栈添加一些空间,以便为其本地数据腾出空间。因此,它会将堆栈指针减少一些,然后使用该空间。
但是,在该空间内,单个对象会正常存储。它们不需要反转,因为堆栈会减少。如果堆栈指针从2400变为2200,我们现在想要将对象放在2300,我们只需将其字节写入内存,从2300开始。
因此,字节序不是受堆栈顺序影响的问题。
答案 1 :(得分:4)
在c中,您将看到char
数组没有字节序问题。字节序不会更改序列。假设它是一个int
,那么该对象的字节将存储在内存中,与字节顺序相关。但对于char
数组,只有按特定顺序排列的字节集合。它没有改变。
请注意,如果您有int
- s的数组,那么这些int
元素将按照您指定的顺序依次存储。但是int
值,它的那些字节 - 将以小端存储。
另一件事是 - char
数组的每个元素都会增加内存。例如,string[0]
的地址将小于string[1]
的地址 - 所以在这里您不能应用字节顺序 - 因为这样会违反此约束。
答案 2 :(得分:0)
Wikipedia很好地描述了字节序,但我无法找到真正的起源。
具有&#34; endianness&#34;的原因,特别是作为大字节序的小尾部是更自然的形式,是处理器如何将字节从存储器移入和移出寄存器的问题 小于本机寄存器宽度的数据总线。
例如,如果数据总线为8位(因此一次只能将1个字节从存储器移到处理器和vv)并且整数宽度为16位,那么:是从存储器移出的第一个字节寄存器中最高有效字节还是最低有效字节?