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

时间:2016-06-11 10:29:35

标签: c pointers malloc dynamic-memory-allocation

我在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个字节,在uint32_t i_ptr之后也开始16个字节。

  1. 这只是一个默认的OS设置,每个堆分配是16个字节吗?
  2. 为什么这种情况与我通过的尺寸无关 到malloc?
  3. 我们如何在0x99ae008和0x99ae018之间插入4个字节的信息?
  4. C来源:

    for k in mieiris['Headword']['Component']:
        try:
            print(k['Text'])
        except KeyError:
            pass
        except UnicodeEncodeError:
            print(unidecode(k['Text']))
    

    CLI输出:

    #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;
    
    }
    

1 个答案:

答案 0 :(得分:2)

malloc返回类型为void *的指针,该指针可以转换为任何其他类型的指针。因此malloc提供了满足任何类型要求的对齐方式。

通常malloc返回一个由段落对齐的地址(在大多数系统中,它等于16个字节)。此外,malloc还分配了段落大小最小的扩展区。所以如果你要写例如

char *p = malloc( 1 );

然后实际上malloc保留了16个字节的范围。