C: ¿Llamar gratis en una variable automática?

int main() { int x = 0; free(x); } 

Esto comstack y parece ser un no-op. ¿Qué sucede realmente? es este comportamiento definido?

¡Gracias!

No, el comportamiento no está definido. Además, el código no se supone que compile.

En primer lugar, el código no debe comstackrse porque contiene una infracción de restricción. La expresión que está pasando como operando a free tiene el tipo int . El parámetro de free tiene void * type. El único caso en el que un valor int puede convertirse implícitamente al tipo void * es cuando el valor int es una Expresión Constante Integral (ICE) con valor 0 . En su caso, x no es un ICE, lo que significa que no se puede convertir implícitamente a void * . La única razón por la que su código comstack es que, por razones históricas (para admitir el código heredado), su comstackdor pasa por alto la violación de restricciones presente en la llamada free(x) . Estoy seguro de que si eleva el nivel de advertencias en su comstackdor, se quejará (al menos con una advertencia). Un comstackdor pedante emitirá inmediatamente un error para free(x) llamada free(x) . Pruebe Comeau Online, por ejemplo en el modo C89 / 90:

 "ComeauTest.c", line 6: error: argument of type "int" is incompatible with parameter of type "void *" free(x); ^ 

(Además, ¿recuerdas incluir stdlib.h antes de llamar free ?)

En segundo lugar, supongamos que el código se comstack, es decir, el comstackdor lo interpreta como free((void *) x) . En este caso, un valor integral no constante x se convierte al tipo de puntero void * . El resultado de esta conversión es la implementación definida. Tenga en cuenta que el idioma garantiza que cuando un ICE con un valor de 0 se convierte en un tipo de puntero, el resultado es un puntero nulo. Pero en su caso, x no es un ICE, por lo que el resultado de la conversión está definido por la implementación. En C no hay garantía de que obtenga un puntero nulo al convertir un entero que no sea ICE con valor 0 a tipo de puntero. En su implementación, probablemente ocurrió que (void *) x con ICE x igual a 0 produce un valor de puntero nulo de tipo void * . Este valor de puntero nulo, cuando se pasa a free , da como resultado una no-op, según la especificación de free .

En el caso general, sin embargo, pasar tal puntero a free dará como resultado un comportamiento indefinido. Los punteros que legalmente puede pasar a free son punteros obtenidos por llamadas anteriores a malloc / calloc / realloc y punteros nulos. Su puntero viola esta restricción en el caso general, por lo que el comportamiento no está definido.

Esto es lo que pasa en tu caso. Pero, una vez más, su código contiene una violación de restricción. E incluso si anula la violación, el comportamiento es indefinido.

Tenga en cuenta que, por cierto, muchas respuestas ya publicadas aquí cometen el mismo error grave. Asumen que (void *) x con cero x se supone que produce un puntero nulo. Esto es absolutamente incorrecto. Nuevamente, el lenguaje no ofrece ninguna garantía sobre el resultado de (void *) x cuando x no es un ICE. (void *) 0 se garantiza que sea un puntero nulo, pero (void *) x con cero x no se garantiza que sea un puntero nulo.

Esto está cubierto en C Preguntas frecuentes http://c-faq.com/null/runtime0.html . Para aquellos interesados ​​en comprender mejor por qué es así, puede ser una buena idea leer la sección completa sobre punteros nulos http://c-faq.com/null/index.html

En su caso, funciona porque llamar a free (NULL) (es decir, free (0)) es un NOOP. Sin embargo, si lo llama con un valor distinto de 0 (NULL), el comportamiento sería indefinido: es probable que se produzcan lockings y / o daños en la memoria.

EDITAR: Como otros han señalado más adelante, free (x) (con x = 0) y free (NULL) no son lo mismo. (Aunque a menudo es 0, el valor del puntero NULL está definido por la implementación y no se puede confiar en él). Consulte la respuesta de AndreyT para obtener una buena aclaración.

Liberar NULL (o 0) no hace nada. Es un no-op.

¿Has intentado subir el nivel de advertencia de tu comstackdor? Por ejemplo, gcc -ansi -pedantic -W -Wall informa:

tmp.c: 6: advertencia: pasar el argumento 1 de ‘free’ hace que el puntero del entero no se convierta

El comportamiento es indefinido. No lo hagas

De la página del hombre free :

free () libera el espacio de memoria apuntado por ptr, que debe haber sido devuelto por una llamada previa a malloc (), calloc () o realloc (). De lo contrario, o si ya se ha llamado a free (ptr) antes, se produce un comportamiento indefinido. Si ptr es NULL, no se realiza ninguna operación.

En su ejemplo, en realidad está llamando a free(0) , ya que free acepta un puntero como argumento. Básicamente, le está diciendo al tiempo de ejecución que libere la memoria en la dirección 0, que no ha sido asignada previamente por malloc .

Dado que ‘0’ es NULL, nada sucederá. (Gracias a los comentarios por señalar mi error tonto).

free () funciona en la memoria asignada dinámicamente, es decir, la memoria asignada con malloc, calloc o realloc. Además, toma un puntero y está pasando el valor de x. No hay ninguna razón para llamarlo en las variables asignadas a la stack que se liberarán cuando la stack se desenrolle y ese comportamiento no esté definido. Siempre es bueno leer la documentación.

http://www.cplusplus.com/reference/clibrary/cstdlib/free/

Debería lanzar una violación de acceso en la mayoría de las architectures. OK, es un 0, así que funciona, pero si no fuera 0, fallaría. Es indefinido No puedes free() una variable asignada de stack.

  

 libre (0);

 "Llamar a la función libre con valor NULL, no tendrá ningún efecto".

En realidad tendrá impacto cuando liberemos la memoria de uso.

Aquí el valor de x es cero, por lo que no hace ningún problema. Si x tiene un valor diferente a

cero, en este caso puede tener fallo de segmentación. Porque el valor de x podría estar usando como

Memoria de representación de algunas otras variables.