2016-06-11 13 views
4

Ich mache einige Beispiel Stack und Heap-Zuweisung auf einem Ubuntu 14.04 VM (Linux 3.13.0-55-generische i686) und ich bin verwirrt von den Speicheradressen für die Heap-Zuweisungen.Was ist der Unterschied zwischen diesen Stack- und Heap-Speicheradressen?

Der unten stehende C-Code weist drei 32-Bit-Bytes ohne Vorzeichen auf dem Stack und drei Zuordnungen auf dem Heap von abnehmenden Größen, 32 Bits, 16 Bits und schließlich 8 Bits zu.

In der Ausgabe unten können wir sehen, dass die Speicheradressen für die drei 32-Bit-Eingänge auf dem Stapel 4 Bits auseinander liegen. uint32_t i ist bei 0xbffd4818 und 4 Adressen später bei 0xbffd481c ist uint32_t j. So können wir hier sehen, dass jedes einzelne Byte des Speichers adressierbar ist und so jeder 4-Byte-Speicherblock 4 Speicheradressen auseinander liegt.

Mit Blick auf die Heap-Zuordnungen können wir sehen, dass uint32_t i_ptr auf 0x99ae008 zeigt und malloc 4 Byte Speicherplatz angefordert, so würde ich erwarten, dass uint16_t j_ptr um 0x99ae00c beginnt, aber es beginnt bei 0x99ae018. Die dritte Heap-Zuweisung für uint8_t k_ptr startet 16 Bytes nach uint16_t i_ptr, die nach uint32_t i_ptr ebenfalls 16 Bytes startet.

  1. Ist es nur eine Standardeinstellung für das Betriebssystem, dass jede Heapzuweisung 16 Byte auseinander liegt?
  2. Warum geschieht das unabhängig von der Größe, die ich an malloc übergeben habe?
  3. Wie können wir 4 Bytes von Informationen zwischen 0x99ae008 und 0x99ae018 passen?

C Quelle:

#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 output:

$ 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 

Antwort

2

malloc gibt einen Zeiger des Typs void *, der mit einem Zeiger von jedem anderen Typ gegossen werden kann. So bietet malloc eine Ausrichtung, die die Anforderungen jeder Art erfüllt.

Normalerweise gibt malloc eine Adresse zurück, die durch den Absatz ausgerichtet wird (in den meisten Systemen entspricht sie 16 Byte). Außerdem weist malloc Extents zu, die ebenfalls eine minimale Größe des Absatzes haben. Also wenn Sie zum Beispiel

char *p = malloc(1); 

schreiben, dann reserviert malloc tatsächlich einen Umfang von 16 Bytes.

+0

Das würde erklären, warum, wenn ich 'malloc (1)' oder 'malloc (2)' den Zeiger immer 16 Bit auseinander, aber was ist mit meinem Aufruf an 'malloc (4)'? j_ptr ist nur 16 Bits im Speicher nach einer 32-Bit-Zuweisung (i_ptr)? – jwbensley

+1

malloc reserviert nicht nur Speicher für die Verwendung durch den Benutzercode, es ist auch Speicher reserviert, um den Heap zu verwalten, zB: so dass free() weiß, was zu tun ist. – Jasen

+1

@jwbensley Ich sehe, dass jede Ausdehnung des zugewiesenen Speichers von 16 Byte unterscheidet: 0x99ae008 // uint32_t i_ptr 0x99ae018 // uint16_t j_ptr 0x99ae028 –

Verwandte Themen