Pregunta ¿Lanzo el resultado de malloc?


En esta pregunta, alguien sugirió en una comentario Eso deberia no lanzar el resultado de malloc, es decir

int *sieve = malloc(sizeof(int) * length);

más bien que:

int *sieve = (int *) malloc(sizeof(int) * length);

Por qué sería este el caso?


2039
2018-03-03 10:13


origen


Respuestas:


No; tú no lo hagas lanzar el resultado, ya que:

  • No es necesario, ya que void * se promueve de forma automática y segura a cualquier otro tipo de puntero en este caso.
  • Agrega desorden al código, los moldes no son muy fáciles de leer (especialmente si el tipo de puntero es largo).
  • Te hace repetir, lo que generalmente es malo.
  • Puede ocultar un error si olvidó incluir <stdlib.h>. Esto puede causar bloqueos (o, peor aún, no causar un bloqueo hasta mucho más tarde en una parte totalmente diferente del código). Considere lo que sucede si los punteros y los números enteros tienen un tamaño diferente; luego ocultas una advertencia al enviar y podrías perder partes de tu dirección devuelta. Nota: a partir de C11 las funciones implícitas se han ido de C, y este punto ya no es relevante ya que no hay una suposición automática de que las funciones no declaradas regresen. int.

Como aclaración, nótese que dije "no echas", no "no lo haces" necesitar para lanzar ". En mi opinión, no incluir el elenco, incluso si lo hiciste bien. Simplemente no hay beneficios al hacerlo, pero hay una serie de riesgos potenciales, e incluir el reparto indica que no sabes sobre los riesgos.

También tenga en cuenta, como comentan los comentaristas, que lo anterior se refiere a la recta C, no C ++. Creo firmemente en C y C ++ como idiomas separados.

Para agregar más, su código repite innecesariamente la información del tipo (int) que puede causar errores. Es mejor eliminar la referencia del puntero que se usa para almacenar el valor de retorno, para "bloquear" los dos juntos:

int *sieve = malloc(length * sizeof *sieve);

Esto también mueve el length al frente para una mayor visibilidad, y elimina los paréntesis redundantes con sizeof; ellos solo son necesarios cuando el argumento es un nombre de tipo. Muchas personas parecen no saber (o ignorar) esto, lo que hace que su código sea más detallado. Recuerda: sizeof no es una función! :)


Mientras se mueve length al frente mayo aumentar la visibilidad en algunos casos excepcionales, también se debe prestar atención que, en el caso general, debería ser mejor escribir la expresión como:

int *sieve = malloc(sizeof *sieve * length);

Desde mantener el sizeof primero, en este caso, asegura que la multiplicación se realiza con al menos size_t mates.

Comparar: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) el segundo puede desbordar el length * width cuando width y length son tipos más pequeños que size_t.


1915
2018-03-03 10:17



En C, no necesita lanzar el valor de retorno de malloc. El puntero al vacío devuelto por malloc se convierte automágicamente al tipo correcto. Sin embargo, si desea que su código compile con un compilador C ++, se necesita un molde. Una alternativa preferida entre la comunidad es usar lo siguiente:

int *sieve = malloc(sizeof *sieve * length);

que además te libera de tener que preocuparte de cambiar el lado derecho de la expresión si alguna vez cambias el tipo de sieve.

Los yesos son malos, como han señalado las personas. Moldes especialmente punteros.


327
2018-03-03 10:17



hacer lanzar, porque:

  • Hace tu código más portátil entre C y C ++, y como muestra la experiencia SO, muchos programadores afirman que escriben en C cuando escriben realmente en C ++ (o C más extensiones de compilador locales).
  • No hacerlo puede esconder un error: tenga en cuenta todos los ejemplos SO de confusión cuando escribir type * versus type **.
  • La idea de que te impide darte cuenta de que no pudiste #include un archivo de encabezado apropiado pierde el bosque por los árboles. Es lo mismo que decir "no te preocupes por el hecho de que no le pidaste al compilador que se queje de no ver los prototipos, ¡ese molesto stdlib.h es lo REALmente importante para recordar!"
  • Fuerza una verificación cruzada cognitiva adicional. Coloca el (supuesto) tipo deseado junto a la aritmética que está haciendo para el tamaño bruto de esa variable. Apuesto a que podrías hacer un estudio SO que demuestre que malloc() los insectos se atrapan mucho más rápido cuando hay un yeso. Al igual que con las afirmaciones, las anotaciones que revelan la intención disminuyen los errores.
  • Repetir de una manera que la máquina puede verificar es a menudo una estupendo idea. De hecho, eso es lo que es una afirmación, y este uso del elenco es una afirmación. Las afirmaciones siguen siendo la técnica más general que tenemos para corregir el código, ya que a Turing se le ocurrió la idea hace tantos años.

291
2018-02-14 16:15



Como se dijo, no es necesario para C, sino para C ++. Si crees que vas a compilar tu código C con un compilador de C ++, por alguna razón, puedes usar una macro en su lugar, como:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

De esta forma, aún puedes escribirlo de una forma muy compacta:

int *sieve = NEW(int, 1);

y compilará para C y C ++.


148
2018-03-03 11:17



Desde el Wikipedia

Ventajas de la fundición

  • Incluir el elenco puede permitir que un programa C o una función compile como C ++.

  • El elenco permite versiones de malloc anteriores a 1989 que originalmente devolvieron un char *.

  • Casting puede ayudar al desarrollador a identificar inconsistencias en el tamaño del tipo si el puntero de destino cambia, particularmente si el puntero se declara lejos de la llamada malloc () (aunque los compiladores modernos y los analizadores estáticos pueden advertir sobre dicho comportamiento sin requerir el reparto).

Desventajas para el casting

  • Según el estándar ANSI C, el elenco es redundante.

  • Agregar el molde puede enmascarar la falla al incluir el encabezado stdlib.h, en   que el prototipo para malloc se encuentra. En ausencia de un   prototipo de malloc, el estándar requiere que el compilador de C   supongamos que malloc devuelve un int. Si no hay yeso, una advertencia es   emitido cuando este entero se asigna al puntero; Sin embargo, con   el elenco, esta advertencia no se produce, ocultando un error. En cierto   arquitecturas y modelos de datos (como LP64 en sistemas de 64 bits, donde   largo y punteros son de 64 bits e int es de 32 bits), este error puede   en realidad dan como resultado un comportamiento indefinido, como el declarado implícitamente   malloc devuelve un valor de 32 bits mientras que la función realmente definida   devuelve un valor de 64 bits. Dependiendo de las convenciones de llamadas y la memoria   diseño, esto puede resultar en aplastamiento de la pila. Este problema es menos probable   pasar desapercibido en los compiladores modernos, ya que producen de manera uniforme   advertencias de que se ha utilizado una función no declarada, por lo que una advertencia   todavía aparece. Por ejemplo, el comportamiento predeterminado de GCC es mostrar un   advertencia que dice "declaración implícita incompatible de built-in   función "independientemente de si el yeso está presente o no.

  • Si el tipo del puntero se cambia en su declaración, uno puede   también, necesita cambiar todas las líneas donde se llama y se emite malloc.

A pesar de que Malloc sin fundición es el método preferido y la mayoría de los programadores experimentados lo eligen, debe usar lo que quiera saber sobre los problemas.

es decir: si necesita compilar el programa C como C ++ (aunque esos son idiomas separados) debe usar malloc con casting.


95
2017-10-09 21:23



En C puedes convertir implícitamente un puntero vacío a cualquier otro tipo de puntero, por lo que no es necesario un lanzamiento. El uso de uno puede sugerir al observador casual que hay alguna razón por la cual se necesita uno, lo que puede ser engañoso.


94
2018-03-03 10:18



No echas el resultado de malloc, porque al hacerlo se agrega un desorden inútil a tu código.

La razón más común por la que las personas arrojan el resultado de malloc es porque no están seguros de cómo funciona el lenguaje C. Esa es una señal de advertencia: si no sabes cómo funciona un mecanismo de lenguaje en particular, entonces no lo hagas Adivina. Búscalo o pregunta en Stack Overflow.

Algunos comentarios:

  • Un puntero de vacío se puede convertir a / desde cualquier otro tipo de puntero sin una conversión explícita (C11 6.3.2.3 y 6.5.16.1).

  • C ++, sin embargo, no permitirá un lanzamiento implícito entre void* y otro tipo de puntero. Entonces en C ++, el elenco habría sido correcto. Pero si programa en C ++, debería usar new y no malloc (). Y nunca debe compilar código C utilizando un compilador C ++.

    Si necesita admitir tanto C como C ++ con el mismo código fuente, use los modificadores del compilador para marcar las diferencias. No intente saciar ambos estándares de idioma con el mismo código, porque no son compatibles.

  • Si un compilador de C no puede encontrar una función porque se olvidó de incluir el encabezado, obtendrá un error de compilador / enlazador al respecto. Entonces, si olvidaste incluir <stdlib.h> eso no es gran cosa, no podrás construir tu programa.

  • En compiladores antiguos que siguen una versión del estándar que tiene más de 25 años, olvidándose de incluir <stdlib.h> daría lugar a un comportamiento peligroso. Porque en ese estándar antiguo, las funciones sin un prototipo visible convierten implícitamente el tipo de retorno a int. Lanzar el resultado de malloc explícitamente ocultaría este error.

    Pero eso realmente no es un problema. No estás usando una computadora de 25 años, ¿por qué usarías un compilador de 25 años?


83
2018-03-20 15:53



En C obtienes una conversión implícita de void* a cualquier otro puntero (de datos).


82
2018-03-03 10:16



Lanzando el valor devuelto por malloc() no es necesario ahora, pero me gustaría agregar un punto que parece que nadie ha señalado:

En los días antiguos, es decir, antes ANSI C proporciona el void * como el tipo genérico de punteros, char * es el tipo para tal uso. En ese caso, el elenco puede cerrar las advertencias del compilador.

Referencia: C Preguntas frecuentes


62
2018-06-09 17:31



No es obligatorio emitir los resultados de malloc, ya que regresa void* y un void*se puede apuntar a cualquier tipo de datos.


48
2018-02-07 22:22