9.4 Manejo de bits
Obtener
el patrón de bits de un número entero sin signo: se acepta una entrada numérica por el teclado hasta que se
pulsa Intro (0x0D). El programa proporciona la imagen del patrón de
bits correspondiente al número introducido.
#include <iostream.h>
int main() { // ==========
unsigned long m, res;
int iter =0;
std::cout << "Introduzca un numero positivo (Intro para terminar):"
<< std::endl;
cin >> m;
if (m < 0) std::cout << "Numero NO valido." << endl;
else if (m <= 255) iter = 8;
else if (m <= 65535) iter = 16;
else if (m <= 4294967295) iter = 32;
for (int i = iter; i > 0; i--) {
res = m & static_cast <unsigned long> (pow(2, i-1));
cout << (res == 0? "-0": "-1");
}
cout << endl;
return 0;
}
Resultados obtenidos con diversos valores:
m = 128 -> -1-0-0-0-0-0-0-0
m = 3250 -> -0-0-0-0-1-1-0-0-1-0-1-1-0-0-1-0
m = 112448 -> -0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-1-0-1-1-0-1-1-1-0-1-0-0-0-0-0-0
A
continuación se incluye una versión perfeccionada del anterior. El
programa acepta igualmente un entero sin signo; a continuación puede
seleccionarse la longitud del patrón de bits correspondiente:
"C" para carácter (8 bits); "S" para unsigned
short (16 bits) y "L" para unsigned log (32 bits).
#include <iostream>
#include <conio.h>
using namespace std;
void mapC(unsigned char); // Prototipos de las funciones que
void mapS(unsigned short); // mostrarán el patrón de bits del
void mapL(unsigned long); // número introducido
int main() {
// ====================
int val;
// variables auxiliares
bool ok = false;
double uDouble = 0;
while (true) {
// bucle principal
cout << "\r\nIntroduzca un numero (Intro para terminar):" <<
endl;
cin >> uDouble;
cout << "\r\nValor seleccionado: " << uDouble << endl;
ok = false;
while ( true ) {
cout << "\r\nSeleccione longitud: C=8 bits, S=16 bits, L=32 bits (ESC = salir)";
val = getch();
if (val == '\x1B') break;
// Escape
else if (val==67 || val==99 || val==83 || val==115 || val==76 || val==108) {
ok = true;
break;
} else {
cout << "\r\nEl caracter NO es valido" << endl;
}
}
if (! ok) break; // terminar ejecucion
if (uDouble < 0 ) {
cout << "\r\nEl numero NO es correcto (solo valores positivos)" << endl;
continue;
}
switch (val) {
case 67: case 99:
// unsigned char (8 bits)
if (uDouble >
UCHAR_MAX) {
cout << "\r\nValor demasiado grande para 8 bits" << endl;
break;
}
mapC((unsigned
char) uDouble); // observe el "casting"
break;
case 83: case 115: // unsigned short (16 bits)
if (uDouble > USHRT_MAX) {
cout << "\r\nValor demasiado grande para 16 bits" << endl;
break;
}
mapS((unsigned short) uDouble);
break;
case 76: case 108: // unsigned long (32 bits)
if (uDouble > ULONG_MAX) {
cout << "\r\nValor demasiado grande para 16 bits" << endl;
break;
}
mapL((unsigned long) uDouble);
break;
}
}
return EXIT_SUCCESS;
}
void mapC (unsigned char value) { // patrón de 8 bits
cout << "\r\n\nMapa de bits = ";
for(int i = 7; i >= 0; i--) cout << ((value & (1 << i)) ? "1" : "0");
cout << "\r\n";
}
void mapS (unsigned short value) { // patrón de 16 bits
cout << "\r\n\nMapa de bits = ";
for(int i = 15; i >= 8; i--) cout << ((value & (1 << i)) ? "1" : "0");
cout << " ";
for(int j = 7; j >= 0; j--) cout << ((value & (1 << j)) ? "1" : "0");
cout << "\r\n";
}
void mapL (unsigned long value) { // patrón de 32 bits
cout << "\r\n\nMapa de bits = ";
for(int i = 31; i >= 24; i--) cout << ((value & (1 << i)) ? "1" : "0");
cout << " ";
for(int j = 23; j >= 16; j--) cout << ((value & (1 << j)) ? "1" : "0");
cout << "-";
for(int k = 15; k >= 8; k--) cout << ((value & (1 << k)) ? "1" : "0");
cout << " ";
for(int l = 7; l >= 0; l--) cout << ((value & (1 << l)) ? "1" : "0");
cout << "\r\n";
}
Resultados para diversos valores de entrada:
128 y "C" --> Mapa de bits = 10000000
128 y "S" --> Mapa de bits = 00000000 10000000
255 y "S" --> Mapa de bits = 00000000 11111111
256 y "S" --> Mapa de bits = 00000001 00000000
4,294,967,040 y "L" --> Mapa de bits = 11111111 11111111-11111111 00000000
Comentario:
Se ha dispuesto un control para verificar que la cantidad
numérica está dentro del rango permitido a la longitud del patrón escogido.
Este control se realiza mediante las constantes manifiestas UCHAR_MAX, USHRT_MAX
y ULONG_MAX ( 2.2.4).
La cantidad introducida se asocia inicialmente a un número
suficientemente grande (un double de 64 bitrs) para albergar cualquier
entero. Posteriormente se realiza un casting adecuado a la longitud
elegida; a continuación se invoca la función que muestra el patrón de bits
según la longitud seleccionada. Observe que se supone una distribución
"Big-endian" ( 2.2.6a),
el octeto más significativo se muestra a la izquierda.
El programa puede ser útil para comprobar el resultado de
los "experimentos" y ejercicios relativos a los operadores de manejo
de bits ( 4.9.3).