为什么即使是大端计算机也从低位内存读取到高位内存?对于 big-endianness 相反可能更优化
Why even big-endianness computers read from lower to higher memory? For big-endianness opposite could be more optimal
我在 wiki and tried to search for my question, found that post 中读到有关字节序的内容,其中解释了字节序不会影响 C
的内存中结构成员的顺序(从低到高)。
在 wiki 中:
The little-endian system has the property that the same value can be
read from memory at different lengths without using different
addresses
但这只是我们从小地址到大地址读取的情况。
我想知道在哪里(什么架构/语言)使用从高位(明确:大地址)到低位的内存序列?这将使 big-endianness 具有在上面引用的 wiki 中正确提到的相同好处。
也例如它可能意味着在类似于 C
malloc
return 最大地址的语言中,程序将通过执行 received_address--
而不是 ++
(希望我说清楚了).
我无法通过网络搜索找到为什么计算机开发没有走那条路(从大地址到小地址读取内存)(因为如果 wiki 中的那个短语是正确的,它确实没有走)。
据我所知,加法操作CPU比减法更容易完成,因此从低内存到高内存更efficient/optimal,而不是相反。
P.S。
减法通常是反转加法:Does a subtraction take longer than an Add in a CPU?
如果我把你的问题理解为"could CPUs and software be made to go from highest address down instead of lowest up?",答案是肯定的。它是根据人类从 0 开始的惯例完成的,但也有例外。
例如,在大多数系统(如 Unix)中,程序堆栈从上到下延伸,而在 Multics 中,它是从下到上。 Multics 的想法是,如果代码写入数组或结构的末尾,它将写入空堆栈 space,并且不会覆盖位于较低地址的堆栈值,而在 Unix 中,堆栈值在更高的地址被覆盖并且会在 return 上崩溃或允许安全漏洞利用。
对于没有内存映射的旧系统来说,从 0 开始似乎是合理的,因为您无法确定安装了多少内存,因此无法确定最高有效内存地址是多少。对于具有内存映射的系统,没有理由更改该约定。
通常情况下,单词中的字节顺序与您访问单词的顺序之间的联系为零。促使选择单词中的字节顺序的推理/好处等根本不适用于索引数组的方式。
例如Intel 发明(或至少使用)little-endian 使 8008 更像是一个 CPU 与它想要兼容的位串行 ALU 和移位寄存器存储。 (Why is x86 little endian? and see also https://retrocomputing.stackexchange.com/questions/2008/were-people-building-cpus-out-of-ttl-logic-prior-to-the-4004-8080-and-the-6800/8664#8664 显然 Datapoint 希望 Intel 构建一个位串行机器并以 LSB 优先顺序存储跳转目标是为了让他们高兴,即使 CPU 最终不是位-连载。)
当对单独的词进行单独访问时,这显然没有任何意义。
维基百科引用的"advantage"更像是一个"fun fact",不是什么真正值钱的东西。将 ISA 弯曲变形以得到它是没有意义的,因为它会使其他任何东西变得更糟或更昂贵,甚至让人类更难使用。仅当您正在构建一个 CPU 来一次解码一个字节的指令时,并且如果解码无论如何都将是多周期的,则可以将提取与解码重叠(因为进位从低位传播到高位) .
尽管您可能对构建第一个小端 CPU 提出了相同的论点,但当时人们认为大端 "natural" 是 "natural"。
您提出的设计将使一个字的地址成为其最低有效字节的地址。(我认为)。
这更像是 little-endian 关于内存寻址的一切 reversed/flipped/negated。
否则它只是一个软件约定 return 一个指向分配的最后一个指针的指针,这显然不太方便,因为它需要一个偏移量才能使用。但是如果你 return 一个指向分配的最后一个字的指针,你怎么知道调用者想把它当作字而不是字节来对待? malloc
return 一个 void*
。如果您 return 指向分配的最后一个字节的指针,则必须进行数学运算才能获得指向最后一个字的指针。
因此,除非您执行反向小端,否则 return 指向分配缓冲区的第一个(或唯一)byte/word/doubleword/float/whatever 指针以外的任何东西显然更糟,特别是考虑到像 malloc
这样的分配器不知道其调用者将用于访问内存的元素大小。
我认为C 的机器模型与反向小端系统勉强兼容。您希望 arr[i]
表示 *(arr - i)
而不是 arr + i
,并且索引寻址模式可能支持 -
而不是 +
。然后 arr[i]
可以透明地与 malloc
一起工作,return 是指向末尾的指针。但是 C 根据 *(x+y)
定义 x[y]
,并且有代码会注意到差异和中断。
否则,如果寻址仍然像正常一样工作,您是否希望将负索引向上计数为零以从低地址循环到高地址?
如果您的 "normal" 用例是 for(i=0; i<n ; i++)
并访问 arr[-i]
,则其工作方式与在普通计算机上的工作方式相同。但是你需要修改你的 C 源代码才能在这样的机器上工作。
或者,如果您想编写 for(i=0 ; i>=-n ; i--)
之类的循环,那么您的最大索引将变为负数,而您的大小仍为正数。这看起来更令人困惑。
(@Alexei Martianov 的回答提出了一个很好的观点:CPU 可能需要在地址生成单元和其他正常 CPU 使用加法器的地方使用二进制减法器。我 想想减法器通常比加法器需要更多的硬件。这在主 ALU 之外,当然必须能够同时支持有效的整数数学运算。)
我在 wiki and tried to search for my question, found that post C
的内存中结构成员的顺序(从低到高)。
在 wiki 中:
The little-endian system has the property that the same value can be read from memory at different lengths without using different addresses
但这只是我们从小地址到大地址读取的情况。
我想知道在哪里(什么架构/语言)使用从高位(明确:大地址)到低位的内存序列?这将使 big-endianness 具有在上面引用的 wiki 中正确提到的相同好处。
也例如它可能意味着在类似于 C
malloc
return 最大地址的语言中,程序将通过执行 received_address--
而不是 ++
(希望我说清楚了).
我无法通过网络搜索找到为什么计算机开发没有走那条路(从大地址到小地址读取内存)(因为如果 wiki 中的那个短语是正确的,它确实没有走)。
据我所知,加法操作CPU比减法更容易完成,因此从低内存到高内存更efficient/optimal,而不是相反。
P.S。 减法通常是反转加法:Does a subtraction take longer than an Add in a CPU?
如果我把你的问题理解为"could CPUs and software be made to go from highest address down instead of lowest up?",答案是肯定的。它是根据人类从 0 开始的惯例完成的,但也有例外。
例如,在大多数系统(如 Unix)中,程序堆栈从上到下延伸,而在 Multics 中,它是从下到上。 Multics 的想法是,如果代码写入数组或结构的末尾,它将写入空堆栈 space,并且不会覆盖位于较低地址的堆栈值,而在 Unix 中,堆栈值在更高的地址被覆盖并且会在 return 上崩溃或允许安全漏洞利用。
对于没有内存映射的旧系统来说,从 0 开始似乎是合理的,因为您无法确定安装了多少内存,因此无法确定最高有效内存地址是多少。对于具有内存映射的系统,没有理由更改该约定。
通常情况下,单词中的字节顺序与您访问单词的顺序之间的联系为零。促使选择单词中的字节顺序的推理/好处等根本不适用于索引数组的方式。
例如Intel 发明(或至少使用)little-endian 使 8008 更像是一个 CPU 与它想要兼容的位串行 ALU 和移位寄存器存储。 (Why is x86 little endian? and see also https://retrocomputing.stackexchange.com/questions/2008/were-people-building-cpus-out-of-ttl-logic-prior-to-the-4004-8080-and-the-6800/8664#8664 显然 Datapoint 希望 Intel 构建一个位串行机器并以 LSB 优先顺序存储跳转目标是为了让他们高兴,即使 CPU 最终不是位-连载。)
当对单独的词进行单独访问时,这显然没有任何意义。
维基百科引用的"advantage"更像是一个"fun fact",不是什么真正值钱的东西。将 ISA 弯曲变形以得到它是没有意义的,因为它会使其他任何东西变得更糟或更昂贵,甚至让人类更难使用。仅当您正在构建一个 CPU 来一次解码一个字节的指令时,并且如果解码无论如何都将是多周期的,则可以将提取与解码重叠(因为进位从低位传播到高位) .
尽管您可能对构建第一个小端 CPU 提出了相同的论点,但当时人们认为大端 "natural" 是 "natural"。
您提出的设计将使一个字的地址成为其最低有效字节的地址。(我认为)。
这更像是 little-endian 关于内存寻址的一切 reversed/flipped/negated。
否则它只是一个软件约定 return 一个指向分配的最后一个指针的指针,这显然不太方便,因为它需要一个偏移量才能使用。但是如果你 return 一个指向分配的最后一个字的指针,你怎么知道调用者想把它当作字而不是字节来对待? malloc
return 一个 void*
。如果您 return 指向分配的最后一个字节的指针,则必须进行数学运算才能获得指向最后一个字的指针。
因此,除非您执行反向小端,否则 return 指向分配缓冲区的第一个(或唯一)byte/word/doubleword/float/whatever 指针以外的任何东西显然更糟,特别是考虑到像 malloc
这样的分配器不知道其调用者将用于访问内存的元素大小。
我认为C 的机器模型与反向小端系统勉强兼容。您希望 arr[i]
表示 *(arr - i)
而不是 arr + i
,并且索引寻址模式可能支持 -
而不是 +
。然后 arr[i]
可以透明地与 malloc
一起工作,return 是指向末尾的指针。但是 C 根据 *(x+y)
定义 x[y]
,并且有代码会注意到差异和中断。
否则,如果寻址仍然像正常一样工作,您是否希望将负索引向上计数为零以从低地址循环到高地址?
如果您的 "normal" 用例是 for(i=0; i<n ; i++)
并访问 arr[-i]
,则其工作方式与在普通计算机上的工作方式相同。但是你需要修改你的 C 源代码才能在这样的机器上工作。
或者,如果您想编写 for(i=0 ; i>=-n ; i--)
之类的循环,那么您的最大索引将变为负数,而您的大小仍为正数。这看起来更令人困惑。
(@Alexei Martianov 的回答提出了一个很好的观点:CPU 可能需要在地址生成单元和其他正常 CPU 使用加法器的地方使用二进制减法器。我 想想减法器通常比加法器需要更多的硬件。这在主 ALU 之外,当然必须能够同时支持有效的整数数学运算。)