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

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:

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

Solution to Exercise 1

El proceso de evaluación ocurre en dos pasos físicos:

  1. Operación aritmética mixta: Al evaluar a / b, el operando a (tipo int, valor 5) se promueve implícitamente a double (5.0) por la regla de conversión aritmética habitual, ya que double tiene mayor jerarquía. La división 5.0 / 2.0 se computa en punto flotante y retorna un valor de tipo double equivalente a 2.5.

  2. Asignación de tipos: El valor resultante (2.5 de tipo double) se asigna a la variable resultado de tipo int. Dado que se asigna un tipo de mayor jerarquía a uno menor, ocurre una coerción implícita hacia abajo que trunca la parte fraccionaria.

Por lo tanto, la variable resultado almacena el valor entero 2.

Solution to Exercise 2

El error reside en la colocación de los paréntesis de agrupación, lo que anula el efecto del cast:

  1. Debido a los paréntesis (total_horas / dias), la división se evalúa primero. Como total_horas y dias son de tipo int, se realiza una división entera: 5 / 2 que resulta en 2.

  2. Posteriormente, se aplica el cast explícito (double) sobre el resultado de la división entera. El valor entero 2 se convierte a 2.0 de tipo double.

  3. El promedio almacenado es 2.0 en lugar del valor preciso de 2.5.

Solución Correcta: Aplicar el cast sobre uno de los operandos individuales antes de la división, permitiendo que la promoción aritmética haga el resto:

double promedio = (double)total_horas / dias; // (double)5.0 / 2 -> 5.0 / 2.0 -> 2.5
Solution to Exercise 3

El comportamiento inesperado ocurre debido a las Conversiones Aritméticas Habituales de C:

  1. En la comparación limite < cantidad, el compilador detecta un operando signado (int limite) y un operando no signado (unsigned int cantidad).

  2. De acuerdo con las reglas de C, el operando signado se promueve implícitamente a tipo no signado (unsigned int) si ambos tienen el mismo tamaño físico.

  3. El valor -5 (cuya representación de bits en complemento a 2 es 0xFFFFFFFB) se reinterpreta directamente como un entero sin signo extremadamente grande: 4294967291.

  4. La comparación física evaluada es 4294967291 < 10, la cual resulta falsa.

Lección de Ingeniería: Nunca debés realizar comparaciones aritméticas mixtas entre tipos signados y no signados sin castear previamente de forma explícita y segura a un tipo común que pueda contener a ambos.


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