数组的元素是不是保证从低地址到高地址存储?

Posted

技术标签:

【中文标题】数组的元素是不是保证从低地址到高地址存储?【英文标题】:Are the elements of an array guaranteed to be stored from lower to higher addresses?数组的元素是否保证从低地址到高地址存储? 【发布时间】:2013-04-30 02:46:40 【问题描述】:

假设我有以下数组:

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

是否总是保证 &list[0] ?

我在使用 C 时认为这是一条硬性规定,但现在必须非常确定,因为当我回答他关于 endianness 的问题时,OP 刚刚问过我这个问题

Little endian or Big endian

让我重新考虑的是stacks can grow up or down 问题。我对此不太确定,因此感谢您的严谨回答。谢谢。

【问题讨论】:

&(list[n]) 我认为每个标准相当于list+n。 C 中的数组索引符号只不过是向指针添加值的简写。以确保+ 工作的方式保留内存 您是在询问事物在 C 中的显示方式或它们在内存中的实际情况? @EricPostpischil 通过评论简单地告诉我你对两者的看法。虽然我对实际记忆更感兴趣。 数组在 C 模型中是连续的和升序的。该标准对物理实现没有任何要求。 您应该指定一个或另一个,以便答案与问题相匹配。如果您想了解两者,请使用两个问题。 【参考方案1】:

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

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

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

【讨论】:

您的回答是否与 Eric Postpischil 的回答相矛盾?请提供更多细节,你们俩。【参考方案2】:

来自 C 标准(“第 6.2.5 节类型”):

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

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

Eric 和 Interjay 所说的,我最初写这篇文章时并没有考虑到这一点,感谢 Eric 和 Interjay,这仅适用于虚拟内存地址。 p>

您的机器和操作系统很可能使用内存管理单元 (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 模型中是连续的,但可能在内存中的任何位置。虽然这不太可能,因为大多数操作系统都实现了某种分页来获得虚拟到物理的映射,但从技术上讲,我认为可能是这种情况......这很好学习考虑,所以感谢小伙子 :)

【讨论】:

【参考方案3】:

如果您询问内存在 C 模型中的显示方式,那么数组似乎在 C 代码中是连续的,并且 C 表达式 &list[0] < &list[1] 为真。

如果您询问实际内存在 C 实现中的显示方式,C 标准不要求在内存中对数组进行任何特定排列。大多数 C 实现对数组使用连续的升序虚拟内存,但降序地址将是一个简单的变体。而且,在物理内存级别,数组通常不是连续的,因为从虚拟内存到物理内存的映射是由操作系统根据可用的内存来确定的,甚至可能在进程执行期间发生变化。

另外,不能保证%p打印的字符串是内存地址。

【讨论】:

只有元素被存储在连续的位置是吗? 地址从高到低或从低到高都无所谓? @Rüppell'sVulture:不,C 标准不保证数组元素是连续存储的。它只要求 C 模型中的指针增量引用连续的数组元素。从 C 指针到机器地址的映射取决于 C 实现。 @Jimbo 您能否在单独的答案中发表您对 Eric 回答的反驳? @Jimbo:所有 C 行为都是用抽象机器描述的。该机器可以以 C 实现所需的任何方式实现。数组地址在 C 模型中必须看起来是连续的,但 C 标准没有对物理存储提出要求。事实上,大多数实现都使用连续的虚拟存储,但底层的物理内存是由操作系统分配的,并不是完全连续的。

以上是关于数组的元素是不是保证从低地址到高地址存储?的主要内容,如果未能解决你的问题,请参考以下文章

c语言问题:c语言中二维数组在内存中怎样存储?

大端小端数据存储方式

Java连载66-数组的两种初始化方式

int[] 数组(从低到高排序)

java 数组从低到高排序

大端模式小端模式高字节序低字节序MSBLSB