¿Cómo obtener la longitud del bloque de memoria después de malloc?

7 minutos de lectura

avatar de usuario
Amumu

Pensé que no podía recuperar la longitud de un bloque de memoria asignado como el simple .length función en Java. Sin embargo, ahora sé que cuando malloc() asigna el bloque, asigna bytes adicionales para contener un número entero que contiene el tamaño del bloque. Este entero se encuentra al principio del bloque; la dirección realmente devuelta a la persona que llama apunta a la ubicación justo después de este valor de longitud. El problema es que no puedo acceder a esa dirección para recuperar la longitud del bloque.

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
        char *str;
        str = (char*) malloc(sizeof(char)*1000);
        int *length;
        length = str-4; /*because on 32 bit system, an int is 4 bytes long*/
        printf("Length of str:%d\n", *length);
        free(str);
}

** Editar: finalmente lo hice. El problema es que sigue dando 0 como la longitud en lugar del tamaño en mi sistema porque mi Ubuntu es de 64 bits. Cambié str-4 a str-8, y ahora funciona.

Si cambio el tamaño a 2000, produce 2017 como longitud. Sin embargo, cuando cambio a 3000, da 3009. Estoy usando GCC.

  • Lo que describa depende completamente de la implementación específica de malloc que almacena la información de la manera que describe. Una implementación de malloc no necesariamente tendría que rastrear cuánta memoria se asignó (poco probable, pero posible dado que la API no lo hace). exigir esta información para ser expuesta a la persona que llama).

    – José

    27 de marzo de 2011 a las 18:01

  • @Joe: por ejemplo, podría implementar con bastante facilidad un asignador basado en grupos en el que, por ejemplo, todas las asignaciones de tamaño 1-8 provienen de un grupo, 9-16 de otro, 17-32 de otro, etc. Entonces, en lugar de el tamaño que se almacena antes que la memoria utilizable, cada asignación podría almacenar un puntero a su grupo. Sin embargo, las grandes asignaciones tendrían que ser tratadas de manera diferente.

    –Steve Jessop

    27 de marzo de 2011 a las 18:44


avatar de usuario
Informate.it

¡No tienes que rastrearlo tú mismo!

size_t malloc_usable_size (void *ptr);

¡Pero devuelve el tamaño real del bloque de memoria asignado! ¡No es el tamaño que le pasaste a malloc!

  • Es importante tener en cuenta que esta función no es parte del estándar C y es una extensión de gnulib

    – Degustación

    24/09/2014 a las 14:54

  • No solo la extensión gnulib

    – CAMOBAP

    1 de enero de 2015 a las 21:39

  • @Hydroper Definitivamente no. Eso detecta GCC, no la biblioteca GNU C. Utilizar __GNU_LIBRARY__ en lugar de.

    – SS Ana

    26 sep 2019 a las 19:36

Lo que estás haciendo definitivamente está mal. Si bien es casi seguro que la palabra justo antes del bloque asignado esté relacionada con el tamaño, aun así probablemente contenga algunas banderas o información adicional en los bits no utilizados. Dependiendo de la implementación, estos datos pueden incluso estar en el elevado bits, lo que haría que leyera la longitud completamente incorrecta. También es posible que las asignaciones pequeñas (por ejemplo, de 1 a 32 bytes) se empaqueten en páginas especiales de bloques pequeños sin encabezados, en cuyo caso la palabra antes del bloque asignado es solo parte de otro bloque y no tiene ningún significado en relación con el tamaño. del bloque que está examinando.

Solo detén esta búsqueda equivocada y peligrosa. Si necesita saber el tamaño de un bloque obtenido por mallocestas haciendo algo mal.

  • Veo. Gracias. Es por eso que tiene un valor diferente para cada tamaño. Solo lo pruebo para ver cómo funciona, y no lo haré en cosas reales. Sin embargo, hay un ejercicio en un libro que requiere implementar malloc() y free() según su implementación explicada, así que solo quiero intentarlo.

    – Amumu

    27 de marzo de 2011 a las 19:22

  • Genial, +1 por hacer esto como parte de la experimentación para “descubrir cómo funciona e intentar implementarlo” en lugar de una piratería horrible.

    – R.. GitHub DEJA DE AYUDAR A ICE

    27 de marzo de 2011 a las 19:38

  • ¿Conoce la forma de filtrar todas las banderas adicionales que agrega al bloque, para obtener el tamaño de memoria puro? Sin embargo, al adivinar, creo que no puedo alterar eso, y entonces tengo que alterar mi propio camino. Además, no sé por qué el tamaño de (int) da 4, mientras que mi sistema es de 64 bits. ¿Hay alguna forma de que sizeof conozca mi sistema de 64 bits?

    – Amumu

    27 de marzo de 2011 a las 19:51

  • sizeof(int) es siempre 4 en la gran mayoría de los sistemas Unix, y probablemente siempre lo será. Utilizar long o mejor aún size_t si desea el tamaño de palabra del sistema.

    – R.. GitHub DEJA DE AYUDAR A ICE

    27 de marzo de 2011 a las 20:11

  • @texasbruce: es intrínsecamente peligroso e incorrecto a menos que esté programando para una versión específica de la implementación específica de C (biblioteca y compilador) que va a usar, y nada más. Y aún así, hacer esa suposición es peligroso y erróneo porque es probable que luego se encuentren errores críticos en la implementación que está utilizando, y que necesitará actualizar, y si las suposiciones que hizo en función de la versión anterior son ya no es cierto con la nueva versión, su programa se romperá catastróficamente.

    – R.. GitHub DEJA DE AYUDAR A ICE

    31 de octubre de 2012 a las 14:44

avatar de usuario
mike m

Le sugiero que cree su propio envoltorio malloc compilando y vinculando un archivo que defina my_malloc() y luego sobrescribiendo el valor predeterminado de la siguiente manera:

// my_malloc.c

#define malloc(sz) my_malloc(sz)

typedef struct {
    size_t size;
} Metadata;

void *my_malloc(size_t sz) {
    size_t size_with_header = sz + sizeof(Metadata);
    void* pointer = malloc(size_with_header);

    // cast the header into a Metadata struct
    Metadata* header = (Metadata*)pointer;
    header->size = sz;    
    // return the address starting after the header 
    // since this is what the user needs
    return pointer + sizeof(Metadata);
}

luego, siempre puede recuperar el tamaño asignado restando el tamaño de (Metadatos), lanzando ese puntero a Metadatos y haciendo metadatos-> tamaño:

Metadata* header = (Metadata*)(ptr - sizeof(Metadata));
printf("Size allocated is:%lu", header->size); // don't quote me on the %lu ;-)

  • Esta es una buena solución que buscar en el código fuente de gcc.

    – SwiftMango

    31 de octubre de 2012 a las 14:27

  • Vale la pena señalar que la memoria devuelta por su contenedor ya no estará alineada en la mayoría de las arquitecturas. Debería saberlo, escribí lo mismo y mi código que se basaba en la alineación me explotó en la cara.

    – Tomás

    28 de junio de 2013 a las 7:53


  • Eso tiene sentido y este código solo debe usarse con fines de depuración bajo estrictas condiciones de control.

    – Mike M.

    26 de julio de 2013 a las 9:00

  • La aritmética de punteros FYI con void* no está permitida, por lo que este código no podrá compilarse en compilaciones compatibles (por ejemplo, GCC con -pedantic).

    –Michael Graczyk

    3 de junio de 2014 a las 6:40

  • @Thomas Para corregir la alineación, puede usar una unión con un miembro de tipo max_align_t: typedef union { size_t size; max_align_t ma; } Metadatos;

    –Fernando Costa Bertoldi

    16/06/2016 a las 22:40


No se supone que hagas eso. Si desea saber cuánta memoria ha asignado, debe realizar un seguimiento de la misma.

Mirar fuera del bloque de memoria devuelto (antes del puntero devuelto por malloc, o después de ese puntero + la cantidad de bytes que solicitó) dará como resultado un comportamiento indefinido. Podría funcionar en la práctica para una implementación de malloc dada, pero no es una buena idea depender de eso.

Esto no es Standard C. Sin embargo, se supone que funciona en los sistemas operativos Windows y podría estar disponible en otros sistemas operativos como Linux (¿msize?) o Mac (¿alloc_size?), también.

size_t _msize( void *memblock );

_msize() devuelve el tamaño de un bloque de memoria asignado en el montón.

Ver este enlace:
http://msdn.microsoft.com/en-us/library/z2s077bc.aspx

avatar de usuario
Oso negro

Esto depende de la implementación.

avatar de usuario
Oléiada

Cada bloque que está asignando está precedido por un descriptor de bloque. El problema es que depende de la arquitectura del sistema. Intente encontrar el tamaño del descriptor de bloque para su propio sistema. Intente echar un vistazo a la página de manual de malloc de su sistema.

  • No necesariamente. Mira mi respuesta.

    – R.. GitHub DEJA DE AYUDAR A ICE

    27 de marzo de 2011 a las 19:01

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad