Campos de bits en C

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);
}
Producción: 

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;
}
Producción: 

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;
}
Producción: 

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() {}
Producción: 

 

 

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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *