¿Cuándo necesito emitir el resultado de malloc en lenguaje C?

Basado en esta vieja pregunta, malloc devuelve un puntero para void .

Se promueve de forma automática y segura a cualquier otro tipo de puntero.

Pero leyendo K&R he encontrado este código siguiente

 char *strdup(char *s) { char *p; /* make a duplicate of s */ p = (char *) malloc(strlen(s)+1) 

¿Cuál es la diferencia?

Para cualquier implementación conforme a C89 o posterior, nunca es necesario lanzar el resultado de malloc() .

La conversión del resultado de malloc() se menciona en la Errata para el lenguaje de progtwigción C, segunda edición :

142 (§6.5, hacia el final): El comentario sobre la conversión del valor de retorno de malloc (“el método correcto es declarar … luego coaccionar explícitamente”) debe ser reescrito. El ejemplo es correcto y funciona, pero el consejo es discutible en el contexto de las normas ANSI / ISO de 1988-1989. No es necesario (dado que la coerción de void * para ALMOSTANYTYPE * es automática), y posiblemente es dañina si malloc , o un proxy para ello, no se declara como devuelto void * . El lanzamiento explícito puede encubrir un error involuntario. Por otro lado, pre-ANSI, el reparto fue necesario, y también está en C ++.

(Ese enlace ya no es válido. La última página de inicio de Dennis Ritchie ya está aquí ; apunta a una ubicación actualizada de la página de inicio del libro, pero ese enlace también es inválido).

La mejor práctica es asignar el resultado de una llamada malloc() directamente a un objeto puntero, y dejar que la conversión implícita de void* se encargue de la consistencia del tipo. La statement de malloc() debe hacerse visible a través de #include .

(Es apenas concebible que desee utilizar malloc() en un contexto donde se necesita una conversión explícita. El único caso que se me ocurre es pasar el resultado de malloc() directamente a una función variadic que necesita un argumento de puntero tipo distinto de void* . En un caso tan inusual y artificial, la conversión puede evitarse asignando el resultado a un objeto puntero y pasando el valor de ese objeto a la función.)

Las únicas buenas razones para emitir el resultado de malloc() son (a) compatibilidad con C ++ (pero la necesidad de escribir código que compile como C y como C ++ más raro de lo que podría esperar) y (b) compatibilidad con pre-ANSI C comstackdores (pero la necesidad de atender a tales comstackdores es rara y cada vez más rara).

En primer lugar: K&R C es antiguo.

En segundo lugar: no sé si ese es el código completo en ese ejemplo, pero en K&R C, se supone que las funciones tienen un valor de retorno int si no se declara lo contrario. Si no está declarando ese malloc , significa que devuelve int en lo que concierne al comstackdor, de ahí el reparto. Tenga en cuenta que este es un comportamiento indefinido incluso en C89 (la primera versión estandarizada) y una práctica extremadamente mala ; pero puede haberlo hecho de esta manera por brevedad, o quizás debido a la pereza, o tal vez por alguna otra razón histórica; No conozco todas las complejidades de K&R C, y podría ser que el void* a los personajes no estuvieran implícitos en ese entonces.

Debo agregar que este es un problema muy serio, ya que int y void* pueden tener diferentes tamaños (y, a menudo, el ejemplo más común es la mayoría de los códigos x86_64, donde los punteros son de 64 bits, pero los ints son de 32 bits) .

ACTUALIZACIÓN: @KeithThompson me ha informado que el código es de la 2ª edición y que se ha declarado malloc allí. Ese es (a diferencia de la 1ª ed.) Todavía relevante, aunque muy desactualizado en algunos lugares.

Supongo que el reparto probablemente fue hecho por compatibilidad con comstackdores no conformes, lo que importaba en ese momento, ya que muchos comstackdores [¿la mayoría?] Aún no estaban completamente conformes. Hoy en día, tendría que salir de su camino para encontrar uno que necesitaría el reparto (y no, los comstackdores de C ++ no cuentan; son comstackdores de C ++, no comstackdores de C).

Las personas que desean (o pueden querer) comstackr de forma cruzada C y C ++ a menudo lanzan malloc(.) Porque C ++ no promocionará automáticamente el void* .

Como otros señalan en los viejos tiempos, cuando los prototipos de funciones eran opcionales, el comstackdor supondría que malloc() devolvía int si no había visto el prototipo con resultados de tiempo de ejecución potencialmente catastróficos.

Intento ver algún punto en ese argumento, pero simplemente no puedo creer que tales situaciones ocurran con una regularidad que justifique que las personas en llamas obtengan el casting de malloc(.) .

Mire cualquier pregunta que emita malloc(.) En este sitio y no importa de qué se trate, alguien le pedirá con rabia que retire sus moldes como si les sangrara los ojos.

NB: No hace ningún bien y no hace nada mal al lanzar malloc(.) lo que es un desorden. De hecho, el único argumento (real) que conozco es que lleva a las personas a mirar el reparto y no a mirar el argumento, ¡que es lo que importa!

Vi el código aquí hoy:

 int** x=(int**)malloc(sizeof(int)*n); 

Es muy fácil dejarse llevar por una falsa sensación de seguridad. La sizeof(int) está haciendo (o en este caso no está haciendo) el trabajo para asegurarse de que lo que regresa de malloc(.) correcto para el propósito. (int**) no funciona.

No estoy diciendo que lo lance. Estoy apelando a la calma. Ciertamente, creo que si un novato no llama free(.) Les enseñamos esa lección antes de adentrarnos en los matices de fundir malloc(.) .