Introducción al sistema de los tipos de datos en C++14

El sistema de tipos de datos en C++14 es una parte fundamental del lenguaje que permite a los programadores definir y manipular diferentes tipos de información de manera eficiente y segura. C++14, una versión del estándar C++ publicada en 2014, introduce varias mejoras y nuevas características que refinan y amplían las capacidades del sistema de tipos de datos.

Tipos de Datos Fundamentales

En C++14, los tipos de datos fundamentales incluyen:

  1. Tipos Enteros: int, short, long, long long, unsigned int, unsigned short, unsigned long, unsigned long long.
  2. Tipos de Punto Flotante: float, double, long double.
  3. Tipos de Carácter: char, wchar_t, char16_t, char32_t.
  4. Tipos Booleanos: bool.
  5. Tipos Vacíos: void

A cada tipo de dato se le suele asignar un valor, estos valores en el común de los casos se suelen usar para cálculos, almacenar o imprimir valores. Estos valores están limitados por el tipo de dato asignado. El rango típico puede variar dependiendo de la arquitectura del hardware y software, así como del compilador.

Tipos Enteros

En C++14, los tipos de enteros tienen rangos definidos por la implementación del compilador, pero el estándar proporciona límites mínimos garantizados para cada tipo.

  • signed char: De -127 a 127 (mínimo garantizado, pero suele ser -128 a 127 en la mayoría de las implementaciones)
  • unsigned char: De 0 a 255
  • char:  Típicamente de -128 a 127 o de 0 a 255. Puede variar su comportamiento y actuar como signed char e incluso como unsigned char, dependiendo de su implementación, así como del entorno en que se desarrollar, compila y ejecuta.
  • short: De -32767 a 32767 (mínimo garantizado, pero suele ser -32768 a 32767)
  • unsigned short: de 0 a 65535
  • int: De -32767 a 32767 (mínimo garantizado, pero suele ser -2147483648 a 2147483647)
  • unsigned int: de 0 a 65535 (mínimo garantizado, pero suele ser de 0 a 4294967295)
  • long: de -2147483647 a 2147483647 (mínimo garantizado, pero suele ser -2147483648 a 2147483647)
  • unsigned long: de 0 a 4294967295
  • long long: de -9223372036854775807 a 9223372036854775807 (mínimo garantizado, pero suele ser -9223372036854775808 a 9223372036854775807)
  • unsigned long long: de 0 a 18446744073709551615

El tipo char es considerado un tipo entero. Aunque se usa principalmente para almacenar caracteres, técnicamente es un tipo entero con un tamaño mínimo de 8 bits (1 byte), lo cual le permite almacenar valores numéricos en el rango adecuado.

#include <iostream>

int main() {

// signed char

signed char sc = -128;

std::cout << "signed char: " << static_cast<int>(sc) << std::endl;


// unsigned char

unsigned char uc = 255;

std::cout << "unsigned char: " << static_cast<int>(uc) << std::endl;


// char

char c = 127;

std::cout << "char: " << static_cast<int>(c) << std::endl;


// short

short s = -32768;

std::cout << "short: " << s << std::endl;


// unsigned short

unsigned short us = 65535;

std::cout << "unsigned short: " << us << std::endl;


// int

int i = -32767;

std::cout << "int: " << i << std::endl;


// unsigned int

unsigned int ui = 65535;

std::cout << "unsigned int: " << ui << std::endl;


// long

long l = -2147483647;

std::cout << "long: " << l << std::endl;


// unsigned long

unsigned long ul = 4294967295;

std::cout << "unsigned long: " << ul << std::endl;


// long long

long long ll = -9223372036854775807;

std::cout << "long long: " << ll << std::endl;


// unsigned long long

unsigned long long ull = 18446744073709551615;

std::cout << "unsigned long long: " << ull << std::endl;


system("pause");

return 0;

}


 Resultado:

 


static_cast es una operación de conversión de tipos en C++ que se utiliza para realizar conversiones explícitas entre tipos relacionados. En el contexto de los tipos de enteros, static_cast se utiliza para convertir un valor de un tipo a otro tipo de manera segura y explícita.

std::cout interpreta los tipos char, signed char y unsigned char como caracteres, no como valores numéricos. Esto significa que si intentas imprimir directamente un valor de estos tipos, std::cout mostrará el carácter correspondiente en lugar del valor numérico. 

// Se usa para añadir comentarios, todo lo escrito en el comentario será ignorado por el compilador y no se verá reflejado de ninguna manera en el programa, y tiene generalmente el propósito de ayudar a la persona que está leyendo el código a tener una mayor comprensión de este. El programa puede funcionar sin necesidad de ellos.

Estos son los tamaños en bytes de los tipos de enteros en C++14, según lo definido por el estándar y lo que es común en la mayoría de las implementaciones:

  • signed char: 1 byte

  • unsigned char: 1 byte

  • char: 1 byte

  • short: 2 bytes

  • unsigned short: 2 bytes

  • int: 4 bytes

  • unsigned int: 4 bytes

  • long: 4 bytes (en sistemas de 32 bits) o 8 bytes (en sistemas de 64 bits)

  • unsigned long: 4 bytes (en sistemas de 32 bits) o 8 bytes (en sistemas de 64 bits)

  • long long: 8 bytes

  • unsigned long long: 8 bytes

Puedes usar el operador sizeof en C++ para verificar los tamaños en bytes de estos tipos:


#include <iostream>

int main() {

std::cout << "sizeof(signed char): " << sizeof(signed char) << " bytes" << std::endl;

std::cout << "sizeof(unsigned char): " << sizeof(unsigned char) << " bytes" << std::endl;

std::cout << "sizeof(char): " << sizeof(char) << " bytes" << std::endl;

std::cout << "sizeof(short): " << sizeof(short) << " bytes" << std::endl;

std::cout << "sizeof(unsigned short): " << sizeof(unsigned short) << " bytes" << std::endl;

std::cout << "sizeof(int): " << sizeof(int) << " bytes" << std::endl;

std::cout << "sizeof(unsigned int): " << sizeof(unsigned int) << " bytes" << std::endl;

std::cout << "sizeof(long): " << sizeof(long) << " bytes" << std::endl;

std::cout << "sizeof(unsigned long): " << sizeof(unsigned long) << " bytes" << std::endl;

std::cout << "sizeof(long long): " << sizeof(long long) << " bytes" << std::endl;

std::cout << "sizeof(unsigned long long): " << sizeof(unsigned long long) << " bytes" << std::endl;

system("pause");

return 0;

}

Resultado:


********************

En C++14, los tipos de punto flotante son fundamentales para la representación de números con decimales y para realizar cálculos matemáticos precisos. Estos tipos se utilizan en una amplia variedad de aplicaciones, desde simulaciones científicas hasta gráficos y juegos. Los tipos de punto flotante en C++14 incluyen float, double y long double, cada uno con diferentes niveles de precisión y rango.

 

float:

  • Precisión: Aproximadamente 6-7 dígitos decimales.

  • Rango: Desde aproximadamente 1.2 por 10 elevado a -38 hasta 3.4 por 10 elevado a 38.

  • Memoria: Generalmente ocupa 4 bytes de memoria. 

     

double:

  • Precisión: Aproximadamente 15-16 dígitos decimales.

  • Rango: Desde aproximadamente 2.2 por 10 elevado a -308 hasta 1.8 por 10 elevado a 308.

  • Memoria: Generalmente ocupa 8 bytes de memoria. 

     

long double:

  • Precisión: Aproximadamente 18-19 dígitos decimales (puede variar según el compilador y la arquitectura).

  • Rango: Desde aproximadamente 3.4 por 10 elevado a -4932 hasta 1.2 por 10 elevado a 4932.

  • Memoria: Su tamaño puede variar dependiendo del compilador y la arquitectura del sistema, pero generalmente ocupa 10, 12 o 16 bytes de memoria.

La precisión se refiere al número de dígitos significativos que un tipo de punto flotante puede representar. En otras palabras, es la cantidad de dígitos que se pueden almacenar de manera precisa en el número. Fuera de los dígitos significativos los valores pueden variar considerablemente, y son generalmente un aproximado del valor real. Esto quiere decir que tendrás un mínimo de precisión garantizado.

 

#include <iostream>

int main() {

float numeroFloat = 3.14f;

double numeroDouble = 3.14;

long double numeroLongDouble = 3.14L;


std::cout << "Valor de float: " << numeroFloat << std::endl;

std::cout << "Valor de double: " << numeroDouble << std::endl;

std::cout << "Valor de long double: " << numeroLongDouble << std::endl;


system("pause");

return 0;

}

 Resultado:


float numeroFloat = 3.14f;: Aquí declaramos una variable de tipo float y le asignamos el valor 3.14. El sufijo f indica que el literal es de tipo float. Sin el sufijo, el literal se considera de tipo double.

double numeroDouble = 3.14;: Aquí declaramos una variable de tipo double y le asignamos el valor 3.14. Los literales de punto flotante sin sufijo se consideran de tipo double por defecto.

long double numeroLongDouble = 3.14L;: Aquí declaramos una variable de tipo long double y le asignamos el valor 3.14. El sufijo L indica que el literal es de tipo long double. Sin el sufijo, el literal se considera de tipo double.

Los valores se convierte implícitamente al tipo de variable al cual se le está siendo asignando un valor. Por ejemplo, si asignas un valor de tipo double a una variable definida como tipo float, el valor de tipo double se convertirá implícitamente al de tipo float.

En C++, puedes usar la función typeid de la librería <typeinfo> para obtener el tipo de una variable y luego imprimirlo en la consola. <typeinfo> es parte de la librería estándar de C++14.

 

#include <iostream>

#include <typeinfo>

int main() {

float numeroFloat = 3.14;

double numeroDouble = 3.14L;

long double numeroLongDouble = 3.14f;


std::cout << "Valor de float: " << numeroFloat << ", Tipo: " << typeid(numeroFloat).name() << std::endl;

std::cout << "Valor de double: " << numeroDouble << ", Tipo: " << typeid(numeroDouble).name() << std::endl;

std::cout << "Valor de long double: " << numeroLongDouble << ", Tipo: " << typeid(numeroLongDouble).name() << std::endl;


system("pause");

return 0;

}

 Resultado:


Se escribe el encabezado #include <typeinfo> para habilitar el uso de las funciones de esta librería, como typeid.

.name() es el método usado para adquirir el valor devuelto de la cadena que representa el nombre del tipo asignado como argumento de typeid, typeid(argumento). El formato de esta cadena puede variar dependiendo del compilador. Algunos compiladores pueden devolver nombres de tipos que no son muy legibles. Sin embargo, en la mayoría de los casos, deberías poder identificar claramente los tipos de datos. 

En este ejemplo se asignaron datos con sufijos diferentes al tipo de variable definidos, concluyendo en una conversión implícita de los datos asignados al tipo de variable definido.

*****************

En C++14 podemos trabajar con diferentes tipos de datos de caracteres para manejar caracteres con distintos rangos de representaciones.

    char: Este tipo maneja caracteres ASCII (7 bits), con un rango de 0 a 127.
    wchar_t: Este tipo puede manejar caracteres Unicode básicos (16 bits en muchas implementaciones, como Windows).
    char16_t: Este tipo maneja caracteres Unicode usando 16 bits (UTF-16).
    char32_t: Este tipo maneja caracteres Unicode usando 32 bits (UTF-32).

 

#include <iostream>

#include <locale>

int main() {

char ascii_char = 'A';

wchar_t wide_char = L'Á';

std::locale::global(std::locale(""));


std::cout << "ASCII char: " << ascii_char << '\n';

std::wcout << L"Wide char: " << wide_char << '\n';


system("pause");

return 0;

}

 Resultado:


#include <locale> incluye la librería de localización, que permite configurar la localización del programa para manejar diferentes configuraciones regionales. <locale> es parte de la librería estándar de C++14.

char ascii_char = 'A' declara una variable de tipo char llamada ascii_char y la inicializa con el carácter 'A'.

wchar_t wide_char = L'Á' declara una variable de tipo wchar_t llamada wide_char y la inicializa con el carácter 'Á'. El prefijo L indica que es un carácter ancho (wide character). Los caracteres anchos son especialmente útiles para representar caracteres que no están en el conjunto de caracteres de tipo char, como caracteres acentuados, caracteres de idiomas no latinos (por ejemplo, chino, japonés, árabe), y otros símbolos especiales.

std::locale::global(std::locale("")) establece la localización global del programa a la localización predeterminada del sistema. Esto permite que el programa maneje correctamente caracteres y configuraciones regionales específicas del sistema.

std::cout << "ASCII char: " << ascii_char << '\n' imprime en la consola el texto "ASCII char: " seguido del valor de ascii_char y un salto de línea.

std::wcout << L"Wide char: " << wide_char << '\n' imprime en la consola el texto "Wide char: " seguido del valor de wide_char y un salto de línea. std::wcout se utiliza para imprimir caracteres anchos.

 **********

 El tipo bool se introdujo en C++ para representar valores booleanos, normalmente se usan para manejar los tipos de estados "verdado" y "falso".

#include <iostream>

int main() {

bool LuzEncendida = true;


if (LuzEncendida==true) {

std::cout << "La luz sigue encendida." << std::endl;

}

else {

std::cout << "La luz ya no sigue encendida." << std::endl;

}


system("pause");

return 0;

}

 

Resultado:

 

#include <iostream>

int main() {

bool LuzEncendida = false;


if (LuzEncendida==true) {

std::cout << "La luz sigue encendida." << std::endl;

}

else {

std::cout << "La luz ya no sigue encendida." << std::endl;

}


system("pause");

return 0;

}

 

 Resultado: 

 

bool LuzEncendida = true declara una variable de tipo bool llamada LuzEncendida y se le asigna el valor true.

if es una condición que verifica si LuzEncendida es true. Si es así, imprime "La luz sigue encendida." en la consola. Si LuzEncendida no es true (es decir, es false), entonces se activa else en lugar de if y se imprime "La luz ya no sigue encendida." en la consola.

 

 *********

En C++14, los tipos de datos vacíos son una característica que permite definir clases, estructuras y otros para que no contengan ningún dato como miembro. Estos tipos vacíos pueden ser utilizados en la implementación de patrones de diseño, en la optimización de memoria y en la creación de tipos de datos marcadores (tags) que no requieren almacenamiento. Los tipos de datos vacíos no ocupan espacio en memoria, lo que puede ser beneficioso en situaciones donde se necesita minimizar el uso de memoria. Esto es especialmente útil en sistemas embebidos o en aplicaciones donde el rendimiento es crítico.

 

Comentarios

Entradas populares de este blog

Introducción a la inicialización de estados en una variable en C++14

Introducción a C++14