В чем разница между этими адресами стека и кучи?
Я делаю некоторые примеры размещения в стеке и куче на виртуальной машине Ubuntu 14.04 (Linux 3.13.0-55-generic i686), и меня смущают адреса памяти для распределений кучи.
Приведенный ниже код C выделяет три 32-разрядных беззнаковых целых в стеке и три выделения в куче уменьшающихся размеров: 32 бита, 16 битов и, наконец, 8 битов.
В приведенном ниже выводе мы видим, что адреса памяти для трех 32-битных целых в стеке разделены на 4 бита. uint32_t i находится по адресу 0xbffd4818, а через 4 адреса по адресу 0xbffd481c - uint32_t j. Итак, мы видим здесь, что каждый отдельный байт памяти является адресуемым, и поэтому каждый 4-байтовый блок памяти разделен на 4 адреса памяти.
Глядя на распределение кучи, мы видим, что uint32_t i_ptr указывает на 0x99ae008, а malloc запрашивает 4 байта пространства, поэтому я ожидаю, что uint16_t j_ptr начнется с 0x99ae00c, но начнется с 0x99ae018. Третье выделение кучи для uint8_t k_ptr начинается через 16 байтов после uint16_t i_ptr, которое также начинается через 16 байтов после uint32_t i_ptr.
- Это просто настройка ОС по умолчанию, что каждое выделение кучи составляет 16 байтов друг от друга?
- Почему это происходит независимо от размера, который я передал malloc?
- Как мы можем разместить 4 байта информации между 0x99ae008 и 0x99ae018?
C Источник:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
int main () {
register uint32_t ebp asm ("ebp");
printf("0x%x\n", ebp);
register uint32_t esp asm ("esp");
printf("0x%x\n", esp);
uint32_t i;
printf("%p\n", &i);
uint32_t j;
printf("%p\n", &j);
uint32_t k;
printf("%p\n", &k);
uint32_t *i_ptr = malloc(4);
printf("%p\n", i_ptr);
uint16_t *j_ptr = malloc(2);
printf("%p\n", j_ptr);
uint8_t *k_ptr = malloc(1);
printf("%p\n", k_ptr);
free(i_ptr);
free(j_ptr);
free(k_ptr);
return 0;
}
Выход CLI:
$ gcc -o heap2 heap2.c
$ ./heap2
0xbffd4838 // EBP
0xbffd4800 // ESP
0xbffd4818 // uint32_t i
0xbffd481c // uint32_t j
0xbffd4820 // uint32_t k
0x99ae008 // uint32_t i_ptr
0x99ae018 // uint16_t j_ptr
0x99ae028 // uint8_t k_ptr
1 ответ
malloc возвращает указатель типа void *
это может быть приведено к указателю любого другого типа. Таким образом, malloc обеспечивает выравнивание, которое удовлетворяет требованиям любого типа.
Обычно malloc возвращает адрес, который выровнен по абзацу (в большинстве систем он равен 16 байтам). Более того, malloc выделяет экстенты, которые также имеют минимальный размер абзаца. Так что если напишешь например
char *p = malloc( 1 );
тогда фактически маллок резервирует 16 байт.