Схема памяти Linux (malloc () используется в C, но не начинается с ожидаемого адреса)

Я использовал этот кусок кода:

    int
main(int argc, char *argv[])
{
    int *p;                   // memory for pointer is on "stack"
    p = malloc(sizeof(int));  // malloc'd memory is on "heap"
    assert(p != NULL);
    printf("(pid:%d) addr of p:        %llx\n", (int) getpid(), 
       (unsigned long long) &p);
    printf("(pid:%d) addr stored in p: %llx\n", (int) getpid(), 
       (unsigned long long) p);
    return 0;
}

Однако я получаю:

addr of p:        7ffc0c53e3e0
addr stored in p: 558ae195c260

Теперь, во-первых, поскольку программа только это делает, я не понимаю, почемуmalloc() не начинается с адреса00200000 ? Во-вторых, могу ли я сказать, что7ffc0c53e3e0 адрес находится вheap , а адрес558ae195c260 вstack ? В-третьих, если я угадаю с00200000 Неправильно, есть какая-то логика с адресами, которые я получаю, или это совершенно случайно?

Когда я думаю об этом, адрес даже не 32 бита, это 48 бит. Даже если он должен быть более 32 бит (у меня 8 ГБ памяти, поэтому я считаю, что в любом случае его должно быть больше 32), почему он не выражается в 64 битах, поскольку процессор 64-битный.

Спасибо за помощь.

# malloc memory-management memory-address
Источник
  • 4
    Как вы думаете, почему адрес, возвращаемый malloc() должен начинаться где угодно, например, с 0x00200000? Ничто не говорит о том, где должна быть выделена память кучи, за исключением того, что она не будет размещена, поэтому она перекрывается с любым другим выделенным сегментом памяти. Адрес 0x7FF…, скорее всего, является адресом стека, а не адресом кучи, а адрес 0x558… является адресом кучи, а не адресом стека (это обратное тому, что вы думали). Адрес действительно 64-битный; первые 4 нуля просто опущены как неинтересные.
  • 1
    Включите в свой вопрос программу, которая дала такие результаты. Не просите нас полагаться на то, что, по вашему мнению, означают «адрес p» и «адрес, хранящийся в p».
  • 0
    @KeithThompson Я сделал.
  • 1
    Правильный способ распечатать значение указателя - привести его к (void*) (если оно еще не относится к этому типу) и использовать спецификатор формата %p И ваша программа неполная; отсутствует как минимум 4 обязательных директивы #include И результат, который вы показываете в своем вопросе, не является результатом этой программы. См. Минимальный воспроизводимый пример .
  • 0
    Комментарии в вашей программе, кажется, правильно отвечают на ваш вопрос.
  • 0
    почему вы ждете чего-то? malloc() вернет указатель или указатель NULL. Это все.
Codelisting
за 0 против
Лучший ответ

Linux реализует ASLR , поэтому, насколько мне известно, вы всегда получаете случайные адреса.558ae195c260 фактически размещается в куче черезmalloc() , в то время как7ffc0c53e3e0 выделяется в стеке, когда вы объявляетеint *p; . 48 бит по-прежнему достаточно для 256 ТБ ОЗУ, но помимо этого некоторые архитектуры не позволяют всем адресным строкам быть полными 64 битами (например, AMD64).

Надеюсь, это поможет. Если что-то из того, что я сказал, неверно или вводит в заблуждение, пожалуйста, поправьте меня в комментариях.

за 0 против

Нет,p находится в стеке (или глобальном) и указывает на кучу памяти в куче.

Касательноmalloc() , если вы работаете в ОС, это зависит от ядра и того, как оно управляет памятью.

Наконец, очевидно, что некоторые из ваших данных неверны. Данные 32-битной шины не могут управлять 8 ГБ ОЗУ (не более 2 ^ 32 = 4 ГБ). Однако это имеет смысл в 64-битной шине, потому что 64-битная переменная имеет достаточно места, чтобы содержать адрес 8 ГБ.

Codelisting
Популярные категории
На заметку программисту