这些堆栈和堆内存地址有什么区别?

我正在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个字节的范围.

点赞