Necesito alguna aclaración sobre el casting en C

7 minutos de lectura

Estaba leyendo sobre la mala práctica de emitir el valor de retorno de malloc. Si entendí bien, es absolutamente legal dejar el elenco como se hace implícitamente (y debe dejarse, por otros problemas que podría generar). Bueno, mi pregunta es, ¿cuándo debo emitir mis valores? ¿Hay alguna regla general o algo así? Por ejemplo, este código compila sin ningún error con gcc -W -Wall (excepto sin usar barpero ese no es el punto):

float foo(void) {
    double bar = 4.2;
    return bar;
}

int main(void) {
    double bar = foo();
    return 0;
}

Estoy confundido ahora. ¿Cuáles son las buenas prácticas y las reglas sobre el casting?

Gracias.

Siempre y cuando siempre sugiero que hagas esto explícitamente para mostrar a los demás, o tal vez a ti mismo en el futuro, que tenías la intención de este comportamiento.

Por cierto, la advertencia de gcc para esto es -Wconversion. Desafortunadamente, -Wall y -Wextra todavía dejan muchas buenas advertencias.

Estas son las banderas que uso cuando quiero que gcc sea muy parecido a una pelusa

-pedantic -std=c99 -ggdb3 -O0 -Wall -Wextra -Wformat=2 -Wmissing-include-dirs -Winit-self -Wswitch-default -Wswitch-enum -Wunused-parameter -Wfloat-equal -Wundef -Wshadow -Wlarger-than-1000 -Wunsafe-loop-optimizations -Wbad-function-cast -Wcast-qual -Wcast-align -Wconversion -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpacked -Wpadded -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Winvalid-pch -Wvolatile-register-var -Wstrict-aliasing=2 -Wstrict-overflow=2 -Wtraditional-conversion -Wwrite-strings

También verifico mi código primero con control de cpp que es un analizador de código estático gratuito para C y C++. Muy recomendable.

  • Otro verificador estático útil es férula.

    – Robert S. Barnes

    21 de diciembre de 2009 a las 19:58

  • férula es otra buena, pero encontré cppcheck para detectar más errores.

    – SiegeX

    21 de diciembre de 2009 a las 20:15

  • En realidad, la mayoría de los programadores de Win32 están llenos de errores. Puede usar grandes porciones de la API de Win32 sin conversiones, si es sensato.

    luego

    21 de diciembre de 2009 a las 19:58

  • Es posible que pueda usar una gran cantidad de Win32 sin conversiones, pero WindowProcs y SendMessage siempre volverán para atormentarlo con las conversiones necesarias.

    – sueño relajado

    21 de diciembre de 2009 a las 20:04

  • Muy poco (no leer ninguno) de la programación de Win32 que hago involucra el procesamiento de mensajes. Y muy poco de la API se preocupa por ello.

    luego

    21 de diciembre de 2009 a las 20:06

  • Muchas de las macros como INVALID_HANDLE_VALUE, INVALID_SET_FILE_POINTER son simplemente cosas como ((HANDLE)(LONG_PTR)-1).

    – sueño relajado

    21 de diciembre de 2009 a las 20:15

  • Ocultar una conversión dentro de una macro no significa que no esté usando una conversión.

    – sueño relajado

    21 de diciembre de 2009 a las 20:20

La razón por la que no emite el valor de retorno de malloc es porque siempre está asignando el valor de retorno a un tipo de puntero, y el estándar C permite un void * para ser convertido implícitamente a cualquier otro tipo de puntero. Emitirlo explícitamente es redundante y, por lo tanto, innecesario.

  • De acuerdo, pero si el código alguna vez puede ser procesado por un compilador de C++, entonces la conversión es necesaria después de todo, porque C++ no tiene conversiones automáticas. desde void * (solamente para void *).

    –Jonathan Leffler

    21 de diciembre de 2009 a las 21:19

  • Cierto, pero normalmente con C++ usarías el new operador en lugar de malloc, ¿no? (Soy un programador novato de C++).

    – sueño relajado

    21 de diciembre de 2009 a las 21:26

avatar de usuario
Comunidad

No puede preguntar sobre la fundición en ‘C’ sin entender que la fundición cubre más de un tipo de operación. Hay esencialmente dos, conversión de tipo y coerción de tipo. En C++, debido a que tiene más información de tipo, crea 4 tipos de moldes y los codifica con una notación exclusiva. reinterpret_cast<>, const_cast<>, dynamic_cast<> y static_cast<>. No tienes estos en C ya que todos los moldes tienen la sintaxis (ctype) pero las razones para ellos permanecen y ayuda a comprender por qué se requiere el lanzamiento a pesar de que su pregunta fue sobre ‘C’ específicamente.

La “necesidad” de transmisión estática es lo que muestra en su ejemplo. El compilador los hará por usted, incluso si no lo especifica; sin embargo, suba el nivel de advertencia lo suficiente y el compilador le advertirá si hay una pérdida de precisión, ya que va de doble a flotante (su return bar; declaración). Agregar un molde le dice al compilador que se pretendía perder precisión.

El segundo lanzamiento menos peligroso es un const cast<>. Se usa para eliminar const o volátil de un tipo. Esto ocurre comúnmente donde las estructuras tienen “cachés” internos. Entonces, una persona que llama puede tener una versión const de su estructura, pero una “función interna” necesita actualizar el caché, por lo que tendrá que convertir un puntero a una estructura const a una estructura normal para actualizar un campo interno.

El tipo más peligroso es un elenco de reinterpretación y por qué la gente seguirá y seguirá sobre lo malo que es lanzar. Ahí es donde no está convirtiendo nada, sino diciéndole al compilador que reinterprete un valor como un tipo totalmente diferente. Lo que se muestra a continuación podría haber sido agregado por un programador ingenuo que intentaba deshacerse de un error del compilador.

    char **ptostr = (char **p) "this is not a good idea"; 

Probablemente la solución correcta fue usar un ‘&’ y así es como el casting tiene una mala reputación. Lanzamientos como este pueden usarse para bien o para mal. Lo usé en la respuesta a otra pregunta sobre cómo encontrar la potencia más pequeña de 2 para aprovechar la potencia de la FPU en una CPU. Un mejor ejemplo de cómo se usa para bien es cuando se implementan listas enlazadas. Si los enlaces viven en los propios objetos, debe convertir el puntero del enlace de nuevo en el objeto adjunto (un buen uso para la macro offsetof si los enlaces no pueden estar en la parte superior de la estructura).

Una conversión dinámica no tiene soporte de idioma en C, pero la circunstancia aún ocurre. Si tiene una lista heterogénea, puede verificar que un objeto sea de un tipo determinado usando un campo en el encabezado del enlace de la lista. Implementado manualmente, verificaría que el tipo sea compatible y devolverá NULL si no lo fuera. Esta es una versión especial del elenco de reinterpretación.

Hay muchos patrones de programación sofisticados que requieren conversión, por lo que no diría que la conversión debe evitarse o indica que algo está mal. El problema con ‘C’ es cómo escribes los inseguros exactamente de la misma manera que los seguros. Mantenerlo contenido y limitado es una buena práctica para que pueda asegurarse de hacerlo bien (p. ej., use rutinas de biblioteca, tipeo fuerte y aserciones si puede).

  • De acuerdo, pero si el código alguna vez puede ser procesado por un compilador de C++, entonces la conversión es necesaria después de todo, porque C++ no tiene conversiones automáticas. desde void * (solamente para void *).

    –Jonathan Leffler

    21 de diciembre de 2009 a las 21:19

  • Cierto, pero normalmente con C++ usarías el new operador en lugar de malloc, ¿no? (Soy un programador novato de C++).

    – sueño relajado

    21 de diciembre de 2009 a las 21:26

avatar de usuario
apaderno

Proyectar un resultado solo debe hacerse cuando sea estrictamente necesario; si está usando código desarrollado por dos personas diferentes (como bibliotecas estáticas o bibliotecas dinámicas) y dos funciones no usan valores compatibles, entonces la conversión es la única solución (siempre y cuando no intente convertir una cadena a un número entero).

Antes de utilizar el casting, sería mejor verificar si los tipos de datos utilizados son correctos. En el código de ejemplo (que tiene el propósito de proporcionar un ejemplo), no tiene sentido declarar el valor devuelto como un valor flotante cuando la función devuelve un doble.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad