Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Conversión de Tipos (Casts) en C

Promoción, coerción implícita y conversión explícita de tipos de datos

Universidad Nacional de Río Negro

Prerrequisitos: tipos numéricos, expresiones y rangos de representación.

Objetivos: 1. Identificar una conversión implícita en una expresión. 2. Justificar un cast explícito o rechazarlo por pérdida de información.

Comprobación de salida: compilá una conversión con -Wconversion y explicá el warning obtenido.

Conversión de Tipos (Casts) en C

Introducción

En C, las variables poseen un tipo estático y rígido asignado en su declaración. Sin embargo, en la práctica es extremadamente común necesitar operar con variables de distintos tipos en una misma expresión (por ejemplo, sumar un entero de tipo int con un valor de punto flotante de tipo double).

Para resolver estas situaciones, el compilador aplica reglas automáticas de conversión, o bien nos permite forzar la conversión de manera explícita. Comprender cómo funciona físicamente la conversión de tipos en el hardware es fundamental para evitar pérdidas de precisión silenciosas, desbordamientos (overflows) o comportamientos indefinidos.


Desarrollo

Conversiones Implícitas (Promoción y Coerción)

Las conversiones implícitas son aquellas que el compilador de C realiza de forma automática, sin intervención explícita del programador, al evaluar expresiones mixtas o al realizar asignaciones.

Promoción Entera (Integer Promotion)

Antes de realizar cualquier operación aritmética, C promueve automáticamente los tipos enteros de menor rango (como char, short o tipos enumerados) a int (o a unsigned int si el rango original no cabe en un entero signado). Esto se realiza porque las unidades aritmético-lógicas (ALU) de la CPU operan de forma más eficiente con el tamaño nativo de palabra del procesador.

char a = 10;
char b = 20;
// 'a' y 'b' se promueven internamente a 'int' antes de realizar la suma
int c = a + b;
Conversiones Aritméticas Habituales

Cuando operandos de tipos diferentes interactúan en una expresión aritmética (como +, -, *, /), el compilador promueve el operando de “menor rango” al tipo del operando de “mayor rango”. El orden general de jerarquía de tipos (de menor a mayor) es:

int<unsigned int<long<unsigned long<float<double<long double\text{int} < \text{unsigned int} < \text{long} < \text{unsigned long} < \text{float} < \text{double} < \text{long double}

Si operás un int con un double, el int se convertirá automáticamente a double antes de computar el resultado en punto flotante.

int base = 5;
double factor = 1.5;
// 'base' se promueve a double (5.0) y la operación retorna un double (7.5)
double resultado = base * factor;
Coerción y Truncamiento (“Democión” de Tipos)

El peligro real de las conversiones implícitas ocurre al asignar un tipo de mayor rango a uno de menor rango. En este caso, el compilador realiza una coerción hacia abajo (democión), lo que puede provocar:

  1. Pérdida de Precisión: Al asignar un float o double a un int, la parte decimal se descarta por completo (se trunca hacia cero, no se redondea).

  2. Desbordamiento (Overflow): Si el valor del tipo mayor excede la capacidad del tipo menor, el comportamiento depende de si el tipo de destino es signado o no. En tipos no signados (unsigned), el valor se reduce módulo el tamaño del tipo. En tipos signados, el resultado es comportamiento indefinido (undefined behavior), aunque físicamente suele ocurrir un truncamiento de bits que altera el signo del número.

double pi = 3.14159;
int pi_entero = pi; // pi_entero tomará el valor 3 (truncamiento implícito)
int grande = 300;
char chico =
    grande; // Truncamiento de bits: 300 (0x012C) se reduce a 0x2C (44)

Conversiones Explícitas (El Operador Cast)

Un cast (o conversión explícita) es una instrucción directa del programador al compilador para forzar la conversión de una expresión a un tipo de dato específico.

Sintaxis

La sintaxis del operador cast antepone el tipo de destino entre paréntesis a la expresión a convertir:

(tipo_destino) expresion

El operador cast tiene una precedencia muy alta (operador unario), por lo que se evalúa antes que la mayoría de los operadores aritméticos a menos que utilices paréntesis agrupadores.

Casos de Uso Comunes

El cast explícito se utiliza principalmente en tres escenarios didácticos y de ingeniería:

1. Evitar la División Entera

En C, si dividís dos enteros, el resultado es una división entera que descarta los decimales. Si necesitás la precisión decimal, debés castear al menos uno de los operandos a un tipo de punto flotante para forzar la promoción del otro operando.

int leidos = 3;
int total = 4;
// Sin cast, leidos / total retornaría 0 (división entera)
double porcentaje = (double)leidos / total; // Retorna 0.75
2. Documentar la Pérdida Intencional de Precisión

Castear explícitamente al asignar un tipo grande a uno chico le comunica al compilador (y a futuros desarrolladores) que el truncamiento de datos es intencional, evitando que el compilador emita advertencias (warnings).

double medicion = 99.987;
int parte_entera =
    (int)medicion; // Claridad de diseño: descarta decimales voluntariamente
3. Trabajar con Interfaces Genéricas

Aunque se abordará en profundidad en capítulos avanzados, el cast explícito es fundamental al manipular punteros genéricos (void*) para reinterpretar la dirección física de la memoria.

Conversiones y Representación en Memoria

Las conversiones de tipos no son meramente lógicas; tienen un impacto físico directo en cómo la CPU manipula los bits de las variables en la memoria RAM.

Cast Aritmético vs. Cast de Reinterpretación

Es fundamental diferenciar conceptualmente entre dos tipos de transformaciones:

float f = 3.14f;

int i = (int) f;               /* conversión de valor: trunca a 3 */

int j;
memcpy(&j, &f, sizeof j);      /* reinterpretación de bytes: patrón IEEE 754 de f */

(int) f produce el número 3: es una conversión de valor definida por el lenguaje. memcpy(&j, &f, sizeof j) copia los mismos bytes que forman f y los deja en j como si fueran un int; el resultado es un número grande y sin relación aritmética con 3.14, porque son los bits del formato de punto flotante leídos como enteros. El error típico es escribir int j = *(int *) &f;, que reinterpreta el objeto en el lugar y viola el tipo efectivo (effective type) de f: es comportamiento indefinido por aliasing estricto, aunque compile y a veces “funcione”.

Leer un objeto mediante unsigned char * sí permite inspeccionar sus bytes sin violar el tipo efectivo: es la única excepción que hace el estándar. Eso no habilita a tratar esos bytes como un double * arbitrario: la alineación, el tipo efectivo y el tamaño siguen siendo requisitos al escribir de vuelta. Para copiar una representación, usá memcpy; para convertir un valor, usá una conversión de C.

Mini-ejercicio

Compilá con optimizaciones (-O2) una función que reinterprete un float como int con un cast de puntero (*(int *) &f) en vez de memcpy, y compará el resultado con y sin la opción -fno-strict-aliasing. ¿Por qué el resultado puede diferir aunque el código fuente no haya cambiado?

Conversión entre Signed y Unsigned (Complemento a 2)

Al castear entre enteros signados y no signados del mismo tamaño (por ejemplo, de int a unsigned int), los bits en memoria no se modifican en absoluto. La CPU simplemente reinterpreta el bit más significativo (el bit de signo en complemento a 2) como parte del valor numérico absoluto.

int negativo = -1; // En memoria (32 bits): 0xFFFFFFFF
unsigned int positivo =
    (unsigned int)negativo; // Reinterpretado como 4294967295 (0xFFFFFFFF)

Este tipo de conversiones implícitas o explícitas mal controladas son el origen de graves problemas de seguridad y lazos infinitos cuando se comparan índices de tamaño en expresiones mixtas.


Ejercicios de Autoevaluación


Glosario

Cast (Casteo)
Operación explícita para forzar al compilador a convertir una expresión a un tipo de dato específico.
Coerción (Coercion)
Conversión automática o implícita de tipos realizada por el compilador para compatibilizar operandos en una expresión o asignación.
Promoción Entera
Regla de C que convierte automáticamente tipos enteros pequeños a int o unsigned int antes de evaluarlos.
Democión de Tipos (Truncamiento)
Conversión de un tipo de mayor jerarquía o rango de representación a uno menor, usualmente acompañada de pérdida de datos o precisión.

Síntesis y Resumen

En esta unidad cubriste las conversiones de datos en C:


Referencias y Lecturas Complementarias