6

假设我有以下数组:

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 时,我曾认为这是一条硬性规定,但现在必须非常确定,因为当我回答他关于endianness

小端或大端

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

4

3 回答 3

8

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

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

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

于 2013-05-06T10:58:26.217 回答
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 模型中是连续的,但可能在内存中的任何地方。尽管这不太可能,因为大多数操作系统都实现了某种分页来获得虚拟到物理的映射,但从技术上讲,我认为可能是这种情况……学习考虑这一点很好,所以感谢小伙子 :)

于 2013-05-06T11:00:52.310 回答
4

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

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

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

于 2013-05-06T10:55:24.827 回答