Estoy trabajando en una base de código antigua y casi todas las invocaciones de free () usan un reparto en su argumento. Por ejemplo,
free((float *)velocity);
free((float *)acceleration);
free((char *)label);
donde cada puntero es del tipo correspondiente (y coincidente). No veo ningún punto en hacer esto en absoluto. Es un código muy antiguo, así que me pregunto si es algo de K&R. Si es así, en realidad deseo admitir los compiladores antiguos que pueden haber requerido esto, por lo que no quiero eliminarlos.
¿Hay alguna razón técnica para usar estos moldes? Ni siquiera veo una gran razón pragmática para usarlos. ¿Cuál es el punto de recordarnos el tipo de datos justo antes de liberarlo?
EDITAR: Esta pregunta no es un duplicado de la otra pregunta. La otra pregunta es un caso especial de esta pregunta, que creo que es obvio si los votantes cercanos leen todas las respuestas.
Colofón: le doy a la "respuesta constante" la marca de verificación porque es una verdadera razón genuina por la que esto podría ser necesario; sin embargo, la respuesta acerca de que es una costumbre anterior a ANSI C (al menos entre algunos programadores) parece ser la razón por la que se usó en mi caso. Un montón de buenos puntos por muchas personas aquí. Gracias por sus aportaciones.
void*
en el C estándar anterior, sino solochar*
. Entonces, si sus hallazgos arqueológicos revelan código que arroja el parámetro a free (), creo que debe ser de ese período o escrito por una criatura de ese momento. Sin embargo, no puedo encontrar ninguna fuente para esto, así que me abstendré de responder.Respuestas:
Es posible que se requiera la conversión para resolver las advertencias del compilador si los punteros son
const
. Aquí hay un ejemplo de código que causa una advertencia sin lanzar el argumento de free:Y el compilador (gcc 4.8.3) dice:
Si usa
free((float*) velocity);
el compilador deja de quejarse.fuente
float*
antes de liberar. Lo intentéfree((void *)velocity);
con gcc 4.8.3. Por supuesto, no funcionaría con un compilador antiguoconst char *p
como argumento y luego lo libera, lo correcto a hacer no es para echarp
achar*
antes de llamar de forma gratuita. Es no declararlo como tomarconst char *p
en primer lugar, ya que modifica*p
y debe declararse como corresponde. (Y si se necesita un puntero constante en lugar de un puntero para constante,int *const p
no es necesario lanzar ya que en realidad es legal y, por lo tanto, funciona bien sin el yeso)Pre-estándar C no tenía
void*
sino solochar*
, por lo que tuvo que emitir todos los parámetros pasados. Si se encuentra con el antiguo código C, por lo tanto, puede encontrar dichos modelos.Pregunta similar con referencias .
Cuando se lanzó el primer estándar C, los prototipos para malloc y free cambiaron de tener
char*
a losvoid*
que todavía tienen hoy.Y, por supuesto, en el estándar C, tales modelos son superfluos y solo dañan la legibilidad.
fuente
free
mismo tipo que ya es?free
en el estándar C (no es necesario emitir). No he leído la primera edición, así que no puedo decir si también se confundieron en los tiempos anteriores a los 80.void*
, pero tampoco tenía prototipos de función, porfree
lo que todavía era innecesario presentar el argumento de incluso en K&R (suponiendo que todos los tipos de puntero de datos usaran la misma representación).char *
. ¿Qué sentido tendría en viejos compiladores sinvoid
? ¿Qué lograrían tales moldes?Aquí hay un ejemplo en el que free fallaría sin un elenco:
En C puede obtener una advertencia (obtuvo una en VS2012). En C ++ obtendrá un error.
Dejando a un lado casos raros, el casting simplemente hincha el código ...
Editar: lancé para
void*
noint*
demostrar la falla. Funcionará igual queint*
se convertirávoid*
implícitamente.int*
Código agregadofuente
void *
, sino parafloat *
ychar *
. Esos moldes no son solo extraños, están equivocados.free(p)
fallaría? ¿Daría un error del compilador?const
los punteros calificadores, obviamente.volatile
ha existido desde que C fue estandarizado, si no más. Fue no ha añadido en C99.Razón anterior: 1. Al usar
free((sometype*) ptr)
, el código es explícito sobre el tipo que el puntero debe considerarse como parte de lafree()
llamada. El reparto explícito es útil cuandofree()
se reemplaza con un (hágalo usted mismo)DIY_free()
.A
DIY_free()
era (es) una forma, especialmente en modo de depuración, para hacer análisis en tiempo de ejecución del puntero que se está liberando. Esto a menudo se combina con unDIY_malloc()
para agregar sentencias, recuentos de uso de memoria global, etc. Mi grupo usó esta técnica durante años antes de que aparecieran herramientas más modernas. Obligó a que el elemento que se estaba liberando fuera lanzado al tipo que se asignó originalmente.Moderno: evitación
const
yvolatile
advertencias según lo abordan Manos Nikolaidis @ y @egur . Pensé que iba a notar los efectos de los 3 calificadores :const
,volatile
, yrestrict
.[editar] Agregado
char * restrict *rp2
por @R .. comentariofuente
restrict
no es un problema debido a dónde está ubicado: afecta al objeto,rp
no al tipo señalado. Si en cambio lo tuvieraschar *restrict *rp
, entonces sería importante.Aquí hay otra hipótesis alternativa.
Se nos dice que el programa fue escrito antes de C89, lo que significa que no puede estar trabajando en algún tipo de desajuste con el prototipo de
free
, porque no solo no había tal cosaconst
nivoid *
antes de C89, no había tal cosa como Un prototipo de función anterior a C89.stdlib.h
en sí fue un invento del comité. Si los encabezados del sistema se molestaran en declararfree
, lo habrían hecho así:Ahora, el punto clave aquí es que la ausencia de prototipos de funciones significa que el compilador no realizó ninguna comprobación de tipo de argumento . Aplicó las promociones de argumento por defecto (las mismas que todavía se aplican a las llamadas a funciones variadas) y eso fue todo. La responsabilidad de hacer que los argumentos en cada sitio de llamadas se alineen con las expectativas del destinatario recae completamente en el programador.
Sin embargo, esto todavía no significa que fuera necesario presentar el argumento
free
en la mayoría de los compiladores de K&R. Una función comodebería haber sido compilado correctamente. Así que creo que lo que tenemos aquí es un programa escrito para hacer frente a un compilador con errores para un entorno inusual: por ejemplo, un entorno donde
sizeof(float *) > sizeof(int)
y el compilador no usaría la convención de llamada apropiada para punteros a menos que los eches en el punto de la llamada.No conozco ningún entorno de ese tipo, pero eso no significa que no haya ninguno. Los candidatos más probables que vienen a la mente son los compiladores "C minúsculos" reducidos para micros de 8 y 16 bits a principios de la década de 1980. Tampoco me sorprendería saber que Crays temprano tuvo problemas como este.
fuente
tomas libres solo en punteros no constantes como parámetro. Entonces, en caso de punteros constantes, se requiere una conversión explícita a un puntero no constante.
Incapaz de liberar punteros constantes en C
fuente