Las variables enteras almacenan números enteros dentro de los límites de cada uno de sus tamaños. A su vez, esos tamaños dependen de la plataforma, del compilador, y del número de bits que use por palabra de memoria: 8, 16, 32... No hay reglas fijas para saber el tamaño, y por lo tanto, el mayor número que podemos almacenar en cada tipo entero: short int, int o long int; depende en gran medida del compilador y del sistema operativo. Sólo podemos estar seguros de que el tamaño de un short int es menor o igual que el de un int, y éste a su vez es menor o igual que el de un long int.
Tipo int o entero:
[signed|unsigned] [short|long] int <identificador>[,<identificador2>[,<identificador3>]...];
[signed|unsigned] long [int] <identificador>[,<identificador2>[,<identificador3>]...];
[signed|unsigned] short [int] <identificador>[,<identificador2>[,<identificador3>]...];
|
Veremos cómo averiguar estos valores cuando estudiemos los operadores.
A cierto nivel, podemos considerar los tipos char, short int, int y long int como tipos enteros diferentes. Pero esa diferencia consiste sólo en el tamaño del valor máximo que pueden contener, y en el tamaño que ocupan en memoria, claro.
Este tipo de variables es útil para almacenar números relativamente grandes, pero sin decimales, por ejemplo el dinero que tienes en el banco, (salvo que seas Bill Gates), o el número de lentejas que hay en un kilo de lentejas.
Tipo "long long":
[signed|unsigned] long long [int] <identificador>[,<identificador2>[,<identificador3>]...]; |
Este tipo no pertenece al estandar ANSI, sin embargo, está disponible en compiladores GNU, como el que se usa en Linux o el que usa el propio Dev-C++ (y otros entornos de desarrollo para Windows).
Este tipo ocupa el siguiente puesto en cuanto a tamaño, después de long int. Como en los otros casos, su tamaño no está definido, pero sí sabemos que será mayor o igual que el de long int.
Tipo "float" o coma flotante:
float <identificador>[,<identificador2>[,<identificador3>]...]; |
Las variables de este tipo almacenan números en formato de coma flotante, esto es, contienen un valor de mantisa y otro de exponente, que, para entendernos, codifican números con decimales.
Aunque el formato en que se almacenan estos números en un ordenador es binario, podemos ver cómo es posible almacenar números muy grandes o muy pequeños mediante dos enteros relativamente pequeños, usando potencias en base 10. Por ejemplo, tenemos para la mantisa un valor entero, m, entre -0.99 y 0.99, y para el exponente un valor, e entre -9 y 9.
Los números se interpretan como m x 10e.
Este formato nos permite almacenar números entre -0.99 x 109 y 0.99 x 109. Es decir, entre -990000000 y 99000000.
Y también números tan pequeños como 0.01 x 10-9 ó -0.01 x 10-9. Es decir, como 0,00000000001 ó -0,00000000001.
Esto sólo con tres dígitos decimales, más los signos. Pero en un ordenador se usa aritmética binaria. Por ejemplo, para un tipo float típico de 32 bits, se usa un bit de signo para la mantisa y otro para el exponente, siete bits para el exponente y 23 para la mantisa.
Estas variables son aptas para variables de tipo real, como por ejemplo el cambio entre euros y dólares. O para números muy grandes, como la producción mundial de trigo, contada en granos.
Pero el fuerte de estos números no es la precisión, sino el orden de magnitud, es decir lo grande o pequeño que es el número que codifica. Por ejemplo, la siguiente cadena de operaciones no dará el resultado correcto:
float a = 12335545621232154;
a = a + 1;
a = a - 12335545621232154;
|
Finalmente, "a" valdrá 0 y no 1, como sería de esperar.
Los formatos en coma flotante sacrifican precisión en favor de tamaño. Sin embargo el ejemplo si funcionaría con números más pequeños. Esto hace que las variables de tipo float no sean muy adecuadas para todos los casos, como veremos más adelante.
Puede que te preguntes (alguien me lo ha preguntado), qué utilidad tiene algo tan impreciso. La respuesta es: aquella que tú, como programador, le encuentres. Te aseguro que float se usa muy a menudo. Por ejemplo, para trabajar con temperaturas, la precisión es suficiente para el margen de temperaturas que normalmente manejamos y para almacenar al menos tres decimales. Pero hay millones de otras situaciones en que resultan muy útiles.
Tipo "bool" o Booleano:
bool <identificador>[,<identificador2>[,<identificador3>]...]; |
Las variables de este tipo sólo pueden tomar dos valores true (verdadero) o false (falso). Sirven para evaluar expresiones lógicas. Este tipo de variables se puede usar para almacenar respuestas, por ejemplo: ¿Posees carné de conducir?. O para almacenar informaciones que sólo pueden tomar dos valores, por ejemplo: qué mano usas para escribir. En estos casos debemos acuñar una regla, en este ejemplo, podría ser diestro->true, zurdo->false.
bool respuesta;
bool continuar;
|
Nota: En algunos compiladores de C++ antiguos no existe el tipo bool. Lo lógico sería no usar esos compiladores, y conseguir uno más actual. Pero si esto no es posible, se puede simular este tipo a partir de un enumerado.
enum bool {false=0, true}; |
Tipo "double" o coma flotante de doble precisión:
[long] double <identificador>[,<identificador2>[,<identificador3>]...]; |
Las variables de este tipo almacenan números en formato de coma flotante, mantisa y exponente, al igual que float, pero usan una precisión mayor, a costa de usar más memoria, claro. Son aptos para variables de tipo real. Usaremos estas variables cuando trabajemos con números grandes, pero también necesitemos gran precisión. El mayor espacio para almacenar el número se usa tanto para ampliar el rango de la mantisa como el del exponente, de modo que no sólo se gana en precisión, sino también en tamaño.
Al igual que pasaba con los números enteros, no existe un tamaño predefinido para cada tipo en coma flotante. Lo que sí sabemos es que el tamaño de double es mayor o igual que el de float y el de long double mayor o igual que el de double.
Lo siento, pero no se me ocurre ahora ningún ejemplo en el que sea útil usar uno de estos tipos.
Bueno, también me han preguntado por qué no usar siempre double o long double y olvidarnos de float. La respuesta es que C++ siempre ha estado orientado a la economía de recursos, tanto en cuanto al uso de memoria como al uso de procesador. Si tu problema no requiere la precisión de un double o long double, ¿por qué derrochar recursos? Por ejemplo, en el compilador Dev-C++ float requiere 4 bytes, double 8 y long double 12, por lo tanto, para manejar un número en formato de long double se requiere el triple de memoria y el triple o más tiempo de procesador que para manejar un float.
Como programadores estamos en la obligación de no desperdiciar nuestros recursos, y mucho menos los recursos de nuestros clientes, para los que crearemos nuestros programas. C++ nos dan un gran control sobre estas características, es nuestra responsabilidad aprender a usarlo como es debido.
Tipo "void" o sin tipo:
void <identificador>[,<identificador2>[,<identificador3>]...]; |
En realidad esta sintaxis es errónea: no se pueden declarar variables de tipo void, ya que tal cosa no tiene sentido.
void es un tipo especial que indica la ausencia de tipo. Se usa para indicar el tipo del valor de retorno en funciones que no devuelven ningún valor, y también para indicar la ausencia de parámetros en funciones que no los requieren, (aunque este uso sólo es obligatorio en C, y opcional en C++), también se usará en la declaración de punteros genéricos, aunque esto lo veremos más adelante.
Las funciones que no devuelven valores parecen una contradicción. En lenguajes como Pascal, estas funciones se llaman procedimientos. Simplemente hacen su trabajo, y no revuelven valores. Por ejemplo, una función que se encargue de borrar la pantalla, no tienen nada que devolver, hace su trabajo y regresa. Lo mismo se aplica a las funciones sin parámetros de entrada, el mismo ejemplo de la función para borrar la pantalla no requiere ninguna entrada para poder realizar su cometido.
Tipo "enum" o enumerado:
enum [<identificador_de_enum>] {
<nombre> [= <valor>], ...} <identificador>[,<identificador2>[,<identificador3>]...];
enum <identificador_de_enum> {
<nombre> [= <valor>], ...} [<identificador>[,<identificador2>[,<identificador3>]...]];
|
Se trata de una sintaxis más elaborada que las que hemos visto hasta ahora, pero no te asustes, (si es que te ha asustado esto) cuando te acostumbres a ver este tipo de cosas comprobarás que son fáciles de comprender.
Este tipo nos permite definir conjuntos de constantes enteras, llamados datos de tipo enumerado. Las variables declaradas de este tipo sólo podrán tomar valores dentro del dominio definido en la declaración.
Vemos que hay dos sintaxis. En la primera, el identificador de tipo es opcional, y si lo usamos podremos declarar más variables del tipo enumerado en otras partes del programa:
[enum] <identificador_de_enum> <identificador>[,<identificador2>[,<identificador3>]...]; |
La segunda sintaxis nos permite añadir una lista de variables, también opcional.
De este modo podemos separar la definición del tipo enumerado de la declaración de variables de ese tipo:
enum orden {primero=1, segundo, tercero};
...
enum orden id1, id2, id3;
|
O podemos hacer ambas cosas en la misma sentencia: definición y declaración:
enum orden {primero=1, segundo, tercero} id1, id2, id3; |
Si decidimos no usar un identificador para el enumerado sólo podremos declarar variables en ese momento, y no en otros lugares del programa, ya que no será posible referenciarlo:
enum {primero=1, segundo, tercero} uno, dos; |
Varios identificadores pueden tomar el mismo valor, pero cada identificador sólo puede usarse en un tipo enumerado. Por ejemplo:
enum tipohoras { una=1, dos, tres, cuatro, cinco,
seis, siete, ocho, nueve, diez, once,
doce, trece=1, catorce, quince,
dieciseis, diecisiete, dieciocho,
diecinueve, veinte, ventiuna,
ventidos, ventitres, venticuatro = 0};
|
En este caso, una y trece valen 1, dos y catorce valen 2, etc. Y veinticuatro vale 0. Como se ve en el ejemplo, una vez se asigna un valor a un elemento de la lista, los siguientes toman valores correlativos. Si no se asigna ningún valor, el primer elemento tomará el valor 0.
Los nombres de las constantes pueden utilizarse en el programa, pero no pueden ser leídos ni escritos. Por ejemplo, si el programa en un momento determinado nos pregunta la hora, no podremos responder doce y esperar que se almacene su valor correspondiente. Del mismo modo, si tenemos una variable enumerada con el valor doce y la mostramos por pantalla, se mostrará 12, no doce. Deben considerarse como "etiquetas" que sustituyen a enteros, y que hacen más comprensibles los programas. Insisto en que internamente, para el compilador, sólo son enteros, en el rango de valores válidos definidos en cada enum.
La lista de valores entre las llaves definen lo que se denomina el "dominio" del tipo enumerado. Un dominio es un conjunto de valores posibles para un dato. Una variable del tipo enumerado no podrá tomar jamás un valor fuera del dominio.
Palabras reservadas usadas en este capítulo
Las palabras reservadas son palabras propias del lenguaje de programación. Están reservadas en el sentido de que no podemos usarlas como identificadores de variables o de funciones.
char, int, float, double, bool, void, enum, unsigned, signed, long, short, true y false.
Ir al Principio
Comentarios