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

时间:2013-05-06 10:52:18

标签: c arrays stack memory-address

假设我有以下数组:

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

始终保证& list [0]<& list [1]<& list [2]

我在使用C时认为它是一个严格而快速的规则,但现在必须非常肯定它作为一个OP,当我回答他关于endianness

的问题时就问过我

Little endian or Big endian

让我第二个想法的是stacks can grow up or down问题。我对此并不十分肯定,所以感谢你的严谨答案。谢谢。

3 个答案:

答案 0 :(得分:6)

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

  

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

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

答案 1 :(得分: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!= VM​​A。对于大于页面大小的数组,虽然VMA看起来是连续的,但PMA可能是不相交的并且不正常,如上图所示......

另外,我认为Interjay和Eric更进了一步,并说任何C地址虽然在C模型中是连续的,但可能在内存中的任何地方。虽然这不太可能,因为大多数操作系统实现某种分页以获得虚拟到物理映射,但从技术上来说,我认为这样做...这是很好的学习考虑,所以感谢chaps:)

答案 2 :(得分:4)

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

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

此外,无法保证%p打印的字符串是内存地址。