¿Por qué malloc asigna una cantidad de bytes diferente a la solicitada?
debugging gcc (11)
Tengo este pedazo de código
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(){
void *a, *b;
a = malloc(16);
b = malloc(16);
printf("/n block size (for a): %p-%p : %li", b, a, b-a);
a = malloc(1024);
b = malloc(1024);
printf("/n block size (for a): %p-%p : %li", b, a, b-a);
}
¿No debería esto imprimir el último tamaño de bloque asignado (16 o 1024)? Por el contrario, imprime 24 y 1032, por lo que la cantidad de memoria asignada parece tener 8 bytes adicionales.
Mi problema es (antes de hacer este caso de prueba) que hago malloc()
en una función (1024 bytes) y devuelvo el resultado asignado. Al verificar el tamaño del bloque en la función de retorno, obtengo 516 bloques ... y no entiendo por qué. Supongo que esta podría ser la razón de la corrupción de memoria que ocurre después de hacer algún procesamiento en los búferes asignados :)
Editar: He visto ¿Cómo puedo obtener el tamaño de una matriz desde un puntero en C? y parece preguntar lo mismo, lo siento por reenviar.
He redirigido mi ejemplo a mi código más específico:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
short int * mallocStuff(long int number, short int base){
short int *array;
int size=1024;
array=(short int*)calloc(1,size);
//array=(short int*)malloc(size);
return array;
}
int main(){
short int **translatedArray;
translatedArray=malloc(4*sizeof(short int));
int i;
for(i=0;i<4;i++){
translatedArray[i]=mallocStuff(0,0);
if(i>0)
printf("/n block size (for a): %p-%p : %i",
translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
}
return 0;
}
Y la salida es
block size (for a): 0x804a420-0x804a018 : 516
block size (for a): 0x804a828-0x804a420 : 516
block size (for a): 0x804ac30-0x804a828 : 516
De acuerdo con la publicación anterior que es más grande que 1024. ¿Estoy equivocado?
Antes del puntero se encuentra el tamaño de la siguiente matriz, que es un entero de 32/64 bits (no sé si está firmado o no)
En primer lugar, Malloc no garantiza que dos llamadas malloc sucesivas devuelvan punteros sucesivos.
En segundo lugar, dependiendo de su arquitectura específica, se aplican diferentes reglas de alineación; a veces puede pedir un solo byte, pero la arquitectura prefiere las asignaciones en intervalos de 8 o 4 bytes.
En tercer lugar, malloc necesita una sobrecarga para almacenar qué tan grande es el bloque asignado, etc.
¡No haga suposiciones sobre lo que Malloc está haciendo más allá de lo que dice la documentación!
Lo que malloc devuelve depende de la implementación de malloc y de la arquitectura. Como ya han dicho otros, se garantiza que obtendrá al MENOS la cantidad de memoria solicitada, o NULO. Esta es también la razón por la que a veces, puede escribir más allá del final de una matriz, y no obtener un error de segmentación. Es porque realmente TIENES acceso válido a esta memoria, simplemente no lo sabías.
No hay garantías de que dos llamadas malloc devuelvan bloques exactamente empaquetados; de hecho, no hay ninguna garantía sobre el resultado, excepto que si no es NULL, apuntará a un bloque tan grande como el solicitado.
Internamente, la mayoría de los mallocs contienen datos de trabajo para ayudarlos a administrar el montón. Por ejemplo, esos 8 bytes pueden contener dos punteros: uno apunta al siguiente bloque y otro apunta al bloque anterior. No sé cuáles son esos 8 bytes porque no mencionaste en qué sistema operativo estás ejecutando, pero es perfectamente normal que malloc use algo de memoria detrás de escena.
Algunos asignadores (por ejemplo, en Windows) proporcionan una función de biblioteca para descubrir el tamaño de bloque dado un puntero, sin embargo, algunos no lo hacen, ya que es una característica bastante esotérica.
Si malloc
devuelve algo que no sea nulo, la memoria que ha sido asignada para su programa tiene el tamaño que pasó a malloc
. Tomar la diferencia de puntero entre los valores de retorno de dos llamadas de diferencia a malloc
podría tener cualquier valor y no tiene nada (bueno poco) que ver con el tamaño de bloque del primer bloque asignado.
malloc()
tendrá sus propios gastos generales.
Sin mencionar que no hay garantía de que 2 asignaciones consecutivas estén una junto a la otra para empezar.
La función malloc
siempre asigna un poco más de lo que usted solicita, para almacenar cierta información de contabilidad. Después de todo, cuando llame a free()
necesita saber qué tan grande es el bloque.
Además, generalmente las implementaciones de malloc
redondearán el tamaño solicitado hasta el próximo múltiplo de 8 o 16 o algún otro número redondo.
Actualización : la verdadera respuesta a su pregunta radica en su uso del tipo short int
. Al hacer aritmética de puntero (resta) entre punteros tipeados, C y C ++ devuelven la diferencia en el número de puntas apuntadas. Dado que está apuntando a short int
, que tiene dos bytes de tamaño, el valor devuelto es la mitad de lo que esperaba.
Por otro lado, malloc
siempre asigna una cantidad dada de bytes , sin importar a qué arrojes el resultado para después. Prueba esto:
array=(short int*)malloc(sizeof(short int) * size);
Tienes un error. En lugar de:
translatedArray=malloc(4*sizeof(short int));
Deberías
translatedArray=malloc(4*sizeof(short int*));
Tenga en cuenta el puntero que falta en su código. Sospecho que de ahí proviene su comportamiento observado.
También 0x804a420 - 0x804a018 = 1032
cuenta que 0x804a420 - 0x804a018 = 1032
, no 516
. La fórmula translatedArray[i] - translatedArray[i - 1]
Array translatedArray[i] - translatedArray[i - 1]
le da la cantidad de elementos (breves entradas, o más simplemente, cortos) entre las dos direcciones, no el número de bytes .
malloc () generalmente se implementa dividiendo el montón disponible en fragmentos de varios tamaños. En su caso, malloc () devuelve 2 fragmentos consecutivos de 1024 (o 16) bytes. El espacio de 8 bytes que menciona es utilizado por malloc () para la información de contabilidad.
Vea las notas de implo de malloc () de Doug Lea aquí para comprender lo que está sucediendo detrás de escena: http://g.oswego.edu/dl/html/malloc.html
Encontré esto ... y reviso el enlace a continuación para más información.
Asignación
Un bloque se asigna desde el conjunto libre convirtiendo primero los bytes solicitados a un índice en el conjunto de segmento, usando la siguiente ecuación:
Necesitado = solicitado + 8
Si es necesario <= 16, entonces cubo = 0
Si es necesario> 16, entonces bucket = (log (needed) / log (2) redondeado al entero más cercano) - 3
El tamaño de cada bloque de la lista anclado por el depósito es tamaño de bloque = 2 segmento + 4. Si la lista en el depósito es nula, la memoria se asigna utilizando la subrutina sbrk para agregar bloques a la lista. Si el tamaño del bloque es inferior a una página, se asigna una página con la subrutina sbrk y se agrega a la lista el número de bloques que se obtienen al dividir el tamaño del bloque en el tamaño de la página. Si el tamaño del bloque es igual o mayor que una página, la memoria necesaria se asigna usando la subrutina sbrk, y se agrega un solo bloque a la lista libre para el depósito. Si la lista libre no está vacía, el bloque que encabeza la lista se devuelve a la persona que llama. El siguiente bloque en la lista se convierte en la nueva cabeza.
malloc () asignará un mínimo de 17 bytes, incluso si está escribiendo malloc (0), para mantener la tabla de almacenamiento dinámico (almacenar información sobre qué tan grande es la pila, cuál es la dirección de inicio, etc.)
main()
{
int *p=(int*)malloc(0);
printf("%d/n",p[-1]);//it will give 17 bytes
}