Всегда ли упорядочен адрес памяти последовательно объявленных переменных по убыванию?

Почему шестнадцатеричное значение возвращаемого адреса указателя всегда в порядке убывания? например здесь int a было объявлено ранее int dпоэтому его адрес всегда оказывается больше dи то же самое для &b,&e а также &c,&fЯ хочу знать, что это фиксированное поведение или это зависит от компилятора? я использую gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-1)

#include<stdio.h>

int main(void){
    int a=1;
    int d=1;
    char b='a' ;
    char e='a';
    float c=1.0;
    float f=1.0;
    printf("a=%p\nd=%p\nb=%p\ne=%p\nc=%p\nf=%p\n",&a,&d,&b,&e,&c,&f);
   if (&a>&d)
        printf("&a>&d\n");
    else
    {printf("&a<&d");
    }
   if (&a>&d && &b>&e && &c>&f)
       printf("addresses are in descending order");
   else{
       printf("false");
   }

  return 0;

}

выход:

a=0xbfc6bd98         //a>d
d=0xbfc6bd94         
b=0xbfc6bd9f         //b>e
e=0xbfc6bd9e
c=0xbfc6bd90         //c>f
f=0xbfc6bd8c
&a>&d 
addresses are in descending order

PS: я новичок в c

5 ответов

Решение

Обнаружил, что это хорошо объяснено в " Разбить стек ради удовольствия и прибыли" Алефа Первого. Извлечены самые актуальные детали.


                         /------------------\  lower
                         |                  |  memory
                         |       Text       |  addresses
                         |                  |
                         |------------------|
                         |   (Initialized)  |
                         |        Data      |
                         |  (Uninitialized) |
                         |------------------|
                         |                  |
                         |       Stack      |  higher
                         |                  |  memory
                         \------------------/  addresses

                     Fig. 1 Process Memory Regions

[...]

   The stack consists of logical stack frames that are pushed when calling a
function and popped when returning.  A stack frame contains the parameters to 
a function, its local variables, and the data necessary to recover the 
previous stack frame, including the value of the instruction pointer at the 
time of the function call.

   Depending on the implementation the stack will either grow down (towards
lower memory addresses), or up.  In our examples we'll use a stack that grows
down.  This is the way the stack grows on many computers including the Intel, 
Motorola, SPARC and MIPS processors. 

[...]

   Let us see what the stack looks like in a simple example:

example1.c:
------------------------------------------------------------------------------
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}

void main() {
  function(1,2,3);
}
------------------------------------------------------------------------------

[...]

With that in mind our stack looks like this when function() is called (each
space represents a byte):


bottom of                                                            top of
memory                                                               memory
           buffer2       buffer1   sfp   ret   a     b     c
<------   [            ][        ][    ][    ][    ][    ][    ]

top of                                                            bottom of
stack                                                                 stack

Как видите, новые (локальные) переменные помещаются поверх стека. В зависимости от дизайна архитектуры, стек увеличивается в сторону более высоких адресов памяти или в сторону более низких адресов памяти, последний в вашем случае.

С точки зрения спецификации языка Си, порядок расположения в памяти распределенных впоследствии переменных не определен. Поэтому это зависит...

Вы не можете делать никаких предположений по этому поводу. С некоторыми компиляторами, некоторыми архитектурами и некоторыми переключателями компилятора вы можете видеть это поведение, то есть локальные переменные, размещаемые по последовательно меньшим адресам стека, но оптимизация и другие факторы могут изменить это поведение.

Переменные, адрес которых вы сравниваете, являются локальными переменными, расположенными в стеке. Теперь способ увеличения стека (вверх или вниз) зависит от архитектуры. Похоже, в вашем случае стек растет вниз, поэтому вы видите уменьшение адресов.

Подробнее об этом здесь

Многие ABI определяют стек, который растет вниз.

Грубое и полуточное объяснение (без учета подробностей о различиях со стеками и кучами) таково: вы хотите минимизировать статически распределенные данные в памяти, конфликтующие с данными, которые необходимо динамически распределять. Динамические вещи обычно увеличиваются в размерах при запуске вашей программы. Чтобы максимизировать возможности выделения динамических элементов, статические элементы и динамические элементы обычно располагаются на противоположных концах пространства памяти, а динамические элементы растут по направлению к статическим элементам. В вашей конкретной ситуации это выглядит так, как будто ваш компилятор загружает статический материал с низким объемом памяти и увеличивает динамический материал с конца до начала вашей памяти (в направлении вашего статического материала).

Другие вопросы по тегам