数组元素是否保证按照从低地址到高地址的顺序存储?

6

假设我有以下数组:

int list[3]={2,8,9};
printf("%p,%p,%p",(void*)&list[0],(void*)&list[1],(void*)&list[2]);

在使用C语言时,&list[0]<&list[1]<&list[2]是否总是保证成立?

我曾经认为这是一个硬性规定,但现在有人问我关于字节序的问题,所以我必须非常确定它是否正确。

Little endian or Big endian

让我开始怀疑的是堆栈可以向上或向下增长的问题。我对此不是很确定,因此非常感谢您详细的回答。谢谢。


1
&(list[n]) 我认为标准上等同于 list+n。在 C 中的数组索引符号不过是将值添加到指针的简写方式。内存保留的方式确保了 + 的可用性。 - wirrbel
@EricPostpischil,请在评论中简要谈谈你对两者的看法。虽然我更关心实际内存。 - Rüppell's Vulture
数组在C模型中是连续且升序的。标准对物理实现没有任何要求。 - Eric Postpischil
@EricPostpischil 我必须仔细阅读这两个答案,才能得出结论。即使对于 C 语言,我也觉得数组必须按顺序存储。 - Rüppell's Vulture
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/29479/discussion-between-ruppells-vulture-and-eric-postpischil - Rüppell's Vulture
显示剩余4条评论
3个回答

9
是的,&list[0]<&list[1]&list[1]<&list[2] 是有保证的。当比较同一数组元素的指针时,具有更大下标的元素指针将被认为具有更大的值。这在 C99 6.5.8@5 中有明确规定:

指向具有较大下标值的数组元素的指针比指向同一数组具有较低下标值的元素的指针更大

但是,不能保证使用 %p 的 printf 打印的值也遵循相同的顺序 - 这些值是实现定义的。

你的回答是否与Eric Postpischil的回答相矛盾?请你们两位再多提供一些细节。 - Rüppell's Vulture

5

根据C标准(“第6.2.5节类型”):

...数组类型描述了一组连续分配的非空对象...

数组将在“内存”中连续分配。

Eric和Interjay所说的是,当我最初编写这篇文章时没有考虑到的内容,所以谢谢Eric和Interjay。他们说的是这仅适用于虚拟内存地址。

您的计算机和操作系统很可能使用内存管理单元(MMU),该单元创建虚拟地址空间(您正在其中工作),并将其映射到物理内存中的块大小块(页面)中。

因此,Eric和Interjay所说的是,虽然虚拟地址将是连续的,但它们映射到的物理内存块可能位于不同的地址。

 Virtual               Physical
+----------+           +----------+
|          |           |
| VMA pg 1 |---------->| PMA 88 (VMA1)
|          |           |
+----------+           +----------+
|          |\           ...
| VMA pg 2 | \          ...
|          |  \         ...
+----------+   \        ...
             \  \       ...  big gap in physical
              \  \      ...  memory
               \  \     ...
                \  \    ...
                 \  >--+----------+
                  \    |
                   \   | PMA 999 (VMA2)
                    \  |
                     >-+----------+

因此,对于小数组(小于页面大小),VMA和PMA地址可能都是相同的,尽管最有可能PMA!= VMA。对于大于页面大小的数组,尽管VMA看起来是连续的,但是PMA可能会散乱无序,如上图所示...

此外,我认为Interjay和Eric正在进一步说明任何C地址,虽然在C模型中是连续的,但可能出现在内存的任何位置。虽然这很不可能,因为大多数操作系统实现了某种分页以获得虚拟到物理映射,但技术上可能是这种情况...学会考虑这一点是好的,所以感谢你们 :)


4
如果您询问内存在C模型中的表现方式,那么在C代码中,数组似乎是连续的,而C表达式“&list [0] < &list [1]”为真。
如果您询问C实现中实际内存的外观,则C标准不需要特定的数组排列方式。大多数C实现使用连续上升的虚拟内存来存储数组,但下降地址将是一种简单的变化。在物理内存层面上,数组通常不是连续的,因为从虚拟内存到物理内存的映射由操作系统基于其可用性确定,并且甚至可能在进程执行期间发生更改。
此外,并没有保证由%p打印的字符串是内存地址。

只是元素需要存储在连续的位置上,对吧? - Rüppell's Vulture
地址是高位到低位还是低位到高位并不重要吗? - Rüppell's Vulture
@Rüppell'sVulture:不,C标准并不保证数组元素被连续存储。它只要求在C模型中指针增量引用连续的数组元素。从C指针到机器地址的映射取决于C实现。 - Eric Postpischil
@Jimbo,您能否单独发布一个回应Eric答案的答案? - Rüppell's Vulture
2
@Jimbo:所有的C语言行为都是以抽象机器的形式描述的。该机器可以按照C实现的任何方式进行实现。在C模型中,数组地址必须看起来是连续的,但是C标准并不对物理存储施加要求。事实上,大多数实现使用连续的虚拟存储,但底层物理内存由操作系统分配,并非完全连续。 - Eric Postpischil
@Eric:我明白你的意思,这完全取决于MMU映射。我之前没有考虑到这一点,谢谢Eric。我会删除我之前的评论... - Jimbo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接