En C, podemos especificar el tamaño (en bits) de la estructura y los miembros de la unión. La idea es usar la memoria de manera eficiente cuando sabemos que el valor de un campo o grupo de campos nunca excederá un límite o está dentro de un rango pequeño.
Por ejemplo, considere la siguiente declaración de fecha sin el uso de campos de bits.
C
#include <stdio.h> // A simple representation of the date struct date { unsigned int d; unsigned int m; unsigned int y; }; int main() { printf("Size of date is %lu bytes\n", sizeof(struct date)); struct date dt = { 31, 12, 2014 }; printf("Date is %d/%d/%d", dt.d, dt.m, dt.y); }
Size of date is 12 bytes Date is 31/12/2014
La representación anterior de ‘fecha’ toma 12 bytes en un compilador donde un int sin firmar toma 4 bytes. Como sabemos que el valor de d es siempre de 1 a 31, el valor de m es de 1 a 12, podemos optimizar el espacio usando campos de bits.
Sin embargo, si el mismo código se escribe utilizando int firmado y el valor de los campos va más allá de los bits asignados a la variable, puede suceder algo interesante. Por ejemplo, considere el mismo código pero con números enteros con signo:
C
#include <stdio.h> // Space optimized representation of the date struct date { // d has value between 0 and 31, so 5 bits // are sufficient int d : 5; // m has value between 0 and 15, so 4 bits // are sufficient int m : 4; int y; }; int main() { printf("Size of date is %lu bytes\n", sizeof(struct date)); struct date dt = { 31, 12, 2014 }; printf("Date is %d/%d/%d", dt.d, dt.m, dt.y); return 0; }
Size of date is 8 bytes Date is -1/-4/2014
La salida resulta ser negativa. Lo que sucedió detrás es que el valor 31 se almacenó en un entero con signo de 5 bits que es igual a 11111. El MSB es un 1, por lo que es un número negativo y debe calcular el complemento a 2 del número binario para obtener su valor real, que es lo que se hace internamente. Al calcular el complemento a 2 llegarás al valor 00001 que es equivalente al número decimal 1 y como era un número negativo obtienes un -1. Algo similar sucede con 12, en cuyo caso obtienes una representación de 4 bits como 1100, que al calcular el complemento de 2 obtienes el valor de -4.
A continuación se presentan algunos datos interesantes sobre los campos de bits en C.
1) Se utiliza un campo de bits especial sin nombre de tamaño 0 para forzar la alineación en el siguiente límite. Por ejemplo, considere el siguiente programa.
C
#include <stdio.h> // A structure without forced alignment struct test1 { unsigned int x : 5; unsigned int y : 8; }; // A structure with forced alignment struct test2 { unsigned int x : 5; unsigned int : 0; unsigned int y : 8; }; int main() { printf("Size of test1 is %lu bytes\n", sizeof(struct test1)); printf("Size of test2 is %lu bytes\n", sizeof(struct test2)); return 0; }
Size of test1 is 4 bytes Size of test2 is 8 bytes
2) No podemos tener punteros a miembros de campos de bits, ya que es posible que no comiencen en un límite de bytes.
C
#include <stdio.h> struct test { unsigned int x : 5; unsigned int y : 5; unsigned int z; }; int main() { struct test t; // Uncommenting the following line will make // the program compile and run printf("Address of t.x is %p", &t.x); // The below line works fine as z is not a // bit field member printf("Address of t.z is %p", &t.z); return 0; }
Producción:
prog.c: In function 'main': prog.c:14:1: error: cannot take address of bit-field 'x' printf("Address of t.x is %p", &t.x); ^
3) Está definido por la implementación para asignar un valor fuera de rango a un miembro de campo de bits.
C
#include <stdio.h> struct test { unsigned int x : 2; unsigned int y : 2; unsigned int z : 2; }; int main() { struct test t; t.x = 5; printf("%d", t.x); return 0; }
Producción:
Implementation-Dependent
4) En C++, podemos tener miembros estáticos en una estructura/clase, pero los campos de bits no pueden ser estáticos.
C++
// The below C++ program compiles and runs fine struct test1 { static unsigned int x; }; int main() {}
C++
// But below C++ program fails in the compilation // as bit fields cannot be static struct test1 { static unsigned int x : 5; }; int main() {}
Producción:
prog.cpp:5:29: error: static member 'x' cannot be a bit-field static unsigned int x : 5; ^
5) No se permite la array de campos de bits. Por ejemplo, el siguiente programa falla en la compilación.
C
struct test { unsigned int x[10] : 5; }; int main() { }
Producción:
prog.c:3:1: error: bit-field 'x' has invalid type unsigned int x[10]: 5; ^
Ejercicio:
Prediga la salida de los siguientes programas. Suponga que el int sin signo toma 4 bytes y el int largo toma 8 bytes.
1)
C++
#include <stdio.h> struct test { unsigned int x; unsigned int y : 33; unsigned int z; }; int main() { printf("%lu", sizeof(struct test)); return 0; }
2)
C++
#include <stdio.h> struct test { unsigned int x; long int y : 33; unsigned int z; }; int main() { struct test t; unsigned int* ptr1 = &t.x; unsigned int* ptr2 = &t.z; printf("%d", ptr2 - ptr1); return 0; }
3)
C++
union test { unsigned int x : 3; unsigned int y : 3; int z; }; int main() { union test t; t.x = 5; t.y = 4; t.z = 1; printf("t.x = %d, t.y = %d, t.z = %d", t.x, t.y, t.z); return 0; }
4) Use campos de bits en C para determinar si una máquina es little-endian o big-endian.
Aplicaciones –
- Si el almacenamiento es limitado, podemos optar por el campo de bits.
- Cuando los dispositivos transmiten estado o información codificada en múltiples bits para este tipo de situación, el campo de bits es más eficiente.
- Las rutinas de cifrado necesitan acceder a los bits dentro de un byte en esa situación, el campo de bits es bastante útil.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA