Estoy leyendo un libro ( Programación con subprocesos POSIX de Butenhof, 1997) que usa C, y encontré la siguiente línea:
(void)free(data);
Aquí, data
son solo un puntero a una estructura asignada,
data = malloc(sizeof(my_struct_t));
¿Por qué el resultado de ser free
se arroja al void
?
Desde mi comprensión de C, esto no parece tener sentido por dos razones:
void
El libro fue escrito en 1997. ¿Es esto algún tipo de legado?
El autor menciona que los ejemplos se ejecutaron en Digital Unix 4.0d, pero todavía no puedo imaginar una razón para emitir el resultado de una función si no va a usar ese resultado.
Este yeso no es necesario. Probablemente no lo hubiera sido en ese momento, ya que C se estandarizó en la forma de C89.
Si lo hubiera sido, habría sido debido a una declaración implícita . Esto generalmente significaba que la persona que escribía el código se olvidó de #include <stdlib.h>
y se estaba usando un analizador estático. Esta no es la mejor solución y una idea mucho mejor hubiera sido simplemente #include <stdlib.h>
en su lugar. Aquí hay algunas palabras de C89 sobre la declaración implícita:
Si la expresión que precede a la lista de argumentos entre paréntesis en una llamada de función consta únicamente de un identificador, y si no hay una declaración visible para este identificador, el identificador se declara implícitamente exactamente como si, en el bloque más interno que contiene la llamada de función, la declaración
extern int identifier();
apareció
Pero eso es extraño porque tampoco están emitiendo el resultado de malloc
, y malloc
y free
están en el mismo archivo de encabezado.
También es posible que esto sea solo un error o alguna forma de decirle al lector que free
no devuelve ningún resultado.
Si estamos hablando de la función free
estándar, entonces su prototipo es
void free(void *ptr);
Por lo tanto, el yeso es completamente inútil.
Ahora algunas especulaciones.
Es posible que el autor haya olvidado incluir el encabezado stdlib.h
que declara este prototipo, por lo que el compilador asume que el tipo de retorno es int
. Ahora, durante el análisis estático de este código, el compilador advirtió sobre el valor de retorno no utilizado de lo que cree que es una función no void
. Tales advertencias generalmente se silencian agregando el elenco a void
.
¡Sería una cosa heredada!
Antes de que existiera un estándar C, la función free()
habría sido (implícitamente) de tipo int
, porque todavía no había un void
de tipo confiable para que regresara. No hubo valor devuelto.
Cuando el código se modificó por primera vez para trabajar con los compiladores estándar de C, probablemente no incluía <stdlib.h>
(porque no existía antes del estándar). El código antiguo escribiría extern char *malloc();
(tal vez sin el extern
) para las funciones de asignación (de manera similar para calloc()
y realloc()
), y no necesitaba declarar free()
. Y el código luego convertiría el valor devuelto en el tipo correcto, porque eso era necesario en al menos algunos sistemas (incluido el que aprendí C).
Algún tiempo después, se agregó la conversión (void)
para decirle al compilador (o, más probablemente, a lint
) que "el valor de retorno de free()
se ignora deliberadamente" para evitar una queja. Pero hubiera sido mejor agregar <stdlib.h>
y dejar su declaración extern void free(void *vp);
decirle a lint
o al compilador que no había ningún valor que ignorar.
JFTR: A mediados de los años 80, ICL Perq estaba originalmente en una arquitectura orientada a palabras y la dirección char *
para una ubicación de memoria era un número muy diferente del puntero 'anything_else' a la misma ubicación. Era crucial declarar char *malloc()
de alguna manera; era crucial transmitir el resultado a cualquier otro tipo de puntero. El elenco en realidad cambió el número utilizado por la CPU. (También hubo mucho regocijo cuando la memoria principal de nuestros sistemas se actualizó de 1 MiB a 2 MiB; dado que el kernel usaba alrededor de 3/4 MiB, significaba que los programas de usuario podían usar 1 1/4 MiB antes de la paginación, etc.)