Ahora, antes de que la gente comience a marcar esto como dup, he leído todo lo siguiente, ninguno de los cuales proporciona la respuesta que estoy buscando:
- Preguntas frecuentes de C: ¿Qué hay de malo en emitir el valor de retorno de malloc?
- SO: ¿Debería lanzar explícitamente el valor de retorno de malloc ()?
- SO: Pointer-casts innecesarios en C
- SO: ¿Lanzo el resultado de malloc?
Tanto las preguntas frecuentes de C como muchas respuestas a las preguntas anteriores citan un misterioso error que malloc
el valor de retorno del casting puede ocultar; sin embargo, ninguno de ellos da un ejemplo específico de tal error en la práctica. Ahora preste atención a que dije error , no advertencia .
Ahora dado el siguiente código:
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
Compilar el código anterior con gcc 4.2, con y sin la conversión, da las mismas advertencias, y el programa se ejecuta correctamente y proporciona los mismos resultados en ambos casos.
anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon@anon:~/$ ./nostdlib_malloc
hello
Entonces, ¿alguien puede dar un ejemplo de código específico de un error de compilación o tiempo de ejecución que podría ocurrir debido al malloc
valor de retorno del casting , o es solo una leyenda urbana?
Editar Me he encontrado con dos argumentos bien escritos sobre este tema:
- A favor de la conversión: Aviso de CERT: Transmita inmediatamente el resultado de una llamada a la función de asignación de memoria en un puntero al tipo asignado
- Against Casting (error 404 de 2012-02-14: use la copia de Internet Archive Wayback Machine del 2010-01-27. {2016-03-18: "La página no se puede rastrear ni mostrar debido a robots.txt."})
void
punteros permite compilar el código como C ++; algunas personas dicen que es una característica, yo diría que es un error;)malloc
valor de retorno de la conversión: conversión aint*
un arco de 64 bits.C
noC++
(son dos idiomas diferentes) Así que cualquier discusión (como en algunas de las respuestas) no es relevante para esta pregunta.Respuestas:
No obtendrá un error del compilador , sino una advertencia del compilador . Como dicen las fuentes que cita (especialmente la primera ), puede obtener un error de tiempo de ejecución impredecible al usar el elenco sin incluir
stdlib.h
.Entonces, el error de su lado no es el elenco, sino el olvido de incluir
stdlib.h
. Los compiladores pueden asumir quemalloc
es una función que regresaint
, por lo tanto, convierten elvoid*
puntero realmente devuelto pormalloc
ayint
luego a su tipo de puntero debido a la conversión explícita. En algunas plataformas, losint
punteros pueden ocupar diferentes números de bytes, por lo que las conversiones de tipos pueden provocar daños en los datos.Afortunadamente, los compiladores modernos dan advertencias que apuntan a su error real. Vea el
gcc
resultado que proporcionó: le advierte que la declaración implícita (int malloc(int)
) es incompatible con la declaración integradamalloc
. Por esogcc
parece saberlomalloc
incluso sin élstdlib.h
.Dejar el elenco para evitar este error es básicamente el mismo razonamiento que escribir
if (0 == my_var)
en vez de
if (my_var == 0)
ya que el último podría conducir a un error grave si uno confundiera
=
y==
, mientras que el primero conduciría a un error de compilación. Personalmente, prefiero este último estilo, ya que refleja mejor mi intención y no suelo cometer este error.Lo mismo ocurre con la conversión del valor devuelto por
malloc
: Prefiero ser explícito en la programación y generalmente verifico para incluir los archivos de encabezado para todas las funciones que uso.fuente
stdlib.h
ya es un error en sí mismo, incluso si solo recibe advertencias de "declaración implícita".Uno de los buenos argumentos de alto nivel en contra de emitir el resultado de a
malloc
menudo no se menciona, aunque, en mi opinión, es más importante que los problemas conocidos de nivel inferior (como truncar el puntero cuando falta la declaración).Una buena práctica de programación es escribir código, que sea lo más independiente posible del tipo. Esto significa, en particular, que los nombres de tipos deben mencionarse en el código lo menos posible o mejor no mencionarlos en absoluto. Esto se aplica a conversiones (evite conversiones innecesarias), tipos como argumentos de
sizeof
(evite usar nombres de tipos ensizeof
) y, en general, todas las demás referencias a nombres de tipos.Los nombres de los tipos pertenecen a las declaraciones. En la medida de lo posible, los nombres de tipos deben restringirse a declaraciones y solo a declaraciones.
Desde este punto de vista, este fragmento de código es malo
int *p; ... p = (int*) malloc(n * sizeof(int));
y esto es mucho mejor
int *p; ... p = malloc(n * sizeof *p);
no simplemente porque "no arroja el resultado de
malloc
", sino porque es independiente del tipo (o agnosítico del tipo, si lo prefiere), porque se ajusta automáticamente a cualquier tipo con el quep
se declare, sin requerir ninguna intervención de el usuario.fuente
Se supone que las funciones no prototipadas regresan
int
.Entonces estás lanzando un
int
a un puntero. Si los punteros son más anchos queint
s en su plataforma, este es un comportamiento de alto riesgo.Además, por supuesto, algunas personas consideran que las advertencias son errores, es decir, el código debería compilarse sin ellas.
Personalmente, creo que el hecho de que no necesite lanzar
void *
a otro tipo de puntero es una característica de C, y considero que el código que sí está roto.fuente
void*
.int
". - ¿Quiere decir que es posible cambiar el tipo de retorno de funciones no prototipadas?#ifdef __cplusplus \nextern "C" { \n#endif static inline uint16_t swb(uint16_t a) {return ((a << 8) | ((a >> 8) & 0xFF); } \n#ifdef __cplusplus\n } \n#endif
. Ahora, por qué querrías llamar a malloc en una función estática en línea, realmente no lo sé, pero los encabezados que funcionan en ambos no son desconocidos.Si hace esto al compilar en modo de 64 bits, su puntero devuelto se truncará a 32 bits.
EDITAR: Lo siento por ser demasiado breve. Aquí hay un fragmento de código de ejemplo para fines de discusión.
Suponga que el puntero del montón devuelto es algo más grande de lo que se puede representar en un int, digamos 0xAB00000000.
Si no se crea un prototipo de malloc para devolver un puntero, el valor int devuelto estará inicialmente en algún registro con todos los bits significativos establecidos. Ahora el compilador dice, "bien, ¿cómo convierto un int en un puntero". Eso será una extensión de signo o una extensión cero de los 32 bits de bajo orden que se le ha dicho que malloc "devuelve" omitiendo el prototipo. Dado que int está firmado, creo que la conversión será una extensión de signo, que en este caso convertirá el valor a cero. Con un valor de retorno de 0xABF0000000, obtendrá un puntero distinto de cero que también causará algo de diversión cuando intente eliminar la referencia.
fuente
Una regla de software reutilizable:
En el caso de escribir una función en línea en la que se usó malloc (), para que sea reutilizable también para el código C ++, haga una conversión de tipos explícita (por ejemplo, (char *)); de lo contrario, el compilador se quejará.
fuente
malloc
/free
para ambos es apta para ser mejor que tratar de utilizarmalloc
en C ynew
en C ++, especialmente si las estructuras de datos son compartidos entre C y C ++ código y existe la posibilidad de que un objeto se cree en código C y se publique en código C ++ o viceversa.Un puntero vacío en C se puede asignar a cualquier puntero sin una conversión explícita. El compilador dará una advertencia, pero se puede reutilizar en C ++ mediante la conversión de tipos
malloc()
al tipo correspondiente. Sin fundición de tipos también se puede usar en C , porque C no es una verificación de tipos estricta . Pero C ++ es estrictamente una verificación de tipos, por lo que es necesario escribirmalloc()
en C ++.fuente