我正在Ubuntu 14.04 VM(
Linux 3.13.0-55-generic i686)上进行一些示例堆栈和堆分配,我对堆分配的内存地址感到困惑.
下面的C代码在堆栈上分配三个32位无符号整数,在堆上分配三个大小减小的分配,32位,16位,最后是8位.
在下面的输出中,我们可以看到堆栈上三个32位整数的存储器地址相隔4位. uint32_t i位于0xbffd4818,后面位于0xbffd481c的4个地址是uint32_t j.所以我们在这里可以看到每个单独的存储器字节是可寻址的,因此每个4字节存储器块是4个存储器地址.
查看堆分配虽然我们可以看到uint32_t i_ptr指向0x99ae008并且malloc请求了4个字节的空间,所以我希望uint16_t j_ptr从0x99ae00c开始,但它从0x99ae018开始. uint8_t k_ptr的第三个堆分配在uint16_t i_ptr之后开始16个字节,uint16_t i_ptr也在uint32_t i_ptr之后开始16个字节.
>它只是一个默认的OS设置,每个堆分配是16个字节吗?
>为什么这种情况与我通过的尺寸无关
到malloc?
>我们如何在0x99ae008和0x99ae018之间输入4个字节的信息?
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
最佳答案 malloc返回一个void *类型的指针,它可以被转换为任何其他类型的指针.因此malloc提供满足任何类型要求的对齐.
通常malloc返回一个由段落对齐的地址(在大多数系统中它等于16个字节).此外,malloc还分配了段落大小最小的扩展区.所以如果你会写例如
char *p = malloc( 1 );
那么实际上malloc保留了16个字节的范围.