Bit-field
Declara un miembro de datos de clase con tamaño explícito, en bits. Los miembros de campo de bits adyacentes pueden (o no) ser empaquetados para compartir y distribuirse entre los bytes individuales.
Una declaración de campo de bits es una declaración de miembro de datos de clase que utiliza el siguiente declarador:
identificador
(opcional)
attr
(opcional)
:
tamaño
|
(1) | ||||||||
identificador
(opcional)
attr
(opcional)
:
tamaño
inicializador-entre-llaves-o-igual
|
(2) | (desde C++20) | |||||||
El tipo del campo de bits es introducido por la decl-specifier-seq de la sintaxis de declaración .
| attr | - | (since C++11) secuencia de cualquier número de atributos |
| identifier | - | el nombre del campo de bits que se está declarando. El nombre es opcional: los campos de bits sin nombre introducen la cantidad especificada de bits de relleno . |
| size | - | una expresión constante integral con un valor mayor o igual a cero. Cuando es mayor que cero, este es el número de bits que ocupará este campo de bits. El valor cero solo se permite para campos de bits sin nombre y tiene un significado especial . |
| brace-or-equal-initializer | - | inicializador de miembro predeterminado que se utilizará con este campo de bits |
Contenidos |
Explicación
El tipo de un campo de bits solo puede ser integral (incluyendo bool ) o un tipo de enumeración (posiblemente calificado con cv), un campo de bits sin nombre no puede declararse con un tipo calificado con cv.
Un campo de bits no puede ser un miembro de datos estático .
No existen campos de bits prvalues : la conversión de lvalue a rvalue siempre produce un objeto del tipo subyacente del campo de bits.
El número de bits en un campo de bits establece el límite del rango de valores que puede contener:
#include <iostream> struct S { // campo sin signo de tres bits, los valores permitidos son 0...7 unsigned int b : 3; }; int main() { S s = {6}; ++s.b; // almacenar el valor 7 en el campo de bits std::cout << s.b << '\n'; ++s.b; // el valor 8 no cabe en este campo de bits std::cout << s.b << '\n'; // formalmente definido por la implementación, típicamente 0 }
Salida posible:
7 0
Múltiples campos de bits adyacentes generalmente se empaquetan juntos (aunque este comportamiento está definido por la implementación):
#include <bit> #include <cstdint> #include <iostream> struct S { // normalmente ocupará 2 bytes: unsigned char b1 : 3; // primeros 3 bits (en el 1er byte) son b1 unsigned char : 2; // siguientes 2 bits (en el 1er byte) se bloquean como no utilizados unsigned char b2 : 6; // 6 bits para b2 - no caben en el 1er byte => inicia un 2do unsigned char b3 : 2; // 2 bits para b3 - siguientes (y últimos) bits en el 2do byte }; int main() { std::cout << sizeof(S) << '\n'; // normalmente imprime 2 S s; // establecer valores de campo distinguibles s.b1 = 0b111; s.b2 = 0b101111; s.b3 = 0b11; // mostrar diseño de campos en S auto i = std::bit_cast<std::uint16_t>(s); // normalmente imprime 1110000011110111 // desglose es: └┬┘├┘└┬┘└─┬──┘└┤ // b1 u a b2 b3 // donde "u" marca los no utilizados :2 especificados en la estructura, y // "a" marca el relleno agregado por el compilador para alinear el siguiente campo a byte. // La alineación a byte ocurre porque el tipo de b2 se declara como unsigned char; // si b2 se declarara como uint16_t no habría "a", b2 estaría contiguo a "u". for (auto b = i; b; b >>= 1) // imprimir primero el bit menos significativo std::cout << (b & 1); std::cout << '\n'; }
Salida posible:
2 1110000011110111
El campo de bits especial sin nombre de tamaño cero puede forzar la interrupción del relleno. Especifica que el siguiente campo de bits comienza al inicio de su unidad de asignación:
#include <iostream> struct S { // normalmente ocupará 2 bytes: // 3 bits: valor de b1 // 5 bits: sin usar // 2 bits: valor de b2 // 6 bits: sin usar unsigned char b1 : 3; unsigned char :0; // comenzar un nuevo byte unsigned char b2 : 2; }; int main() { std::cout << sizeof(S) << '\n'; // normalmente imprime 2 // normalmente imprimiría 1 si no fuera por // la ruptura de relleno en la línea 11 }
Salida posible:
2
Si el tamaño especificado del campo de bits es mayor que el tamaño de su tipo, el valor está limitado por el tipo: un
std::
uint8_t
b
:
1000
;
aún mantendría valores en el rango
[
0
,
255
]
. Los bits adicionales son
bits de relleno
.
Debido a que los campos de bits no necesariamente comienzan al principio de un byte, no se puede tomar la dirección de un campo de bits. No son posibles los punteros y las referencias no constantes a campos de bits. Cuando se inicializa una referencia const desde un campo de bits, se crea un temporal (su tipo es el tipo del campo de bits), se copia inicializado con el valor del campo de bits, y la referencia se vincula a ese temporal.
|
No existen inicializadores de miembros por defecto para campos de bits: int b : 1 = 0 ; y int b : 1 { 0 } no son válidas. |
(hasta C++20) |
|
En caso de ambigüedad entre el tamaño del campo de bits y el inicializador de miembro por defecto, se elige la secuencia más larga de tokens que forma un tamaño válido: int a; const int b = 0; struct S { // casos simples int x1 : 8 = 42; // OK; "= 42" es brace-or-equal-initializer int x2 : 8 {42}; // OK; "{42}" es brace-or-equal-initializer // ambigüedades int y1 : true ? 8 : a = 42; // OK; brace-or-equal-initializer está ausente int y2 : true ? 8 : b = 42; // error: no se puede asignar a const int int y3 : (true ? 8 : b) = 42; // OK; "= 42" es brace-or-equal-initializer int z : 1 || new int{0}; // OK; brace-or-equal-initializer está ausente }; |
(desde C++20) |
Notas
Las siguientes propiedades de los campos de bits son definidas por la implementación :
- El valor que resulta de asignar o inicializar un campo de bits con signo con un valor fuera de rango, o de incrementar un campo de bits con signo más allá de su rango.
- Todo sobre los detalles reales de asignación de campos de bits dentro del objeto de clase.
-
- Por ejemplo, en algunas plataformas, los campos de bits no cruzan bytes, en otras sí lo hacen.
- También, en algunas plataformas, los campos de bits se empaquetan de izquierda a derecha, en otras de derecha a izquierda.
En el lenguaje de programación C, el ancho de un campo de bits no puede exceder el ancho del tipo subyacente, y si los campos de bits
int
que no son explícitamente
signed
o
unsigned
son con signo o sin signo está definido por la implementación. Por ejemplo,
int
b
:
3
;
puede tener el rango de valores
[
0
,
7
]
o
[
-
4
,
3
]
en C, pero solo la última opción está permitida en C++.
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 324 | C++98 |
no estaba especificado si el valor de retorno
de una asignación a un campo de bits es un campo de bits |
se añadieron especificaciones de campo de bits para
operadores que pueden retornar lvalues |
| CWG 739 | C++98 |
la signatura de campos de bits que no estaban declarados
signed ni unsigned estaba definida por la implementación |
consistente con los tipos subyacentes |
| CWG 2229 | C++98 | los campos de bits sin nombre podían declararse con un tipo calificado con cv | prohibido |
| CWG 2511 | C++98 | las calificaciones cv no estaban permitidas en tipos de campo de bits |
los campos de bits pueden tener tipos de enumeración
calificados con cv |
Referencias
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 11.4.10 Campos de bits [class.bit]
- Estándar C++20 (ISO/IEC 14882:2020):
-
- 11.4.9 Campos de bits [class.bit]
- Estándar C++17 (ISO/IEC 14882:2017):
-
- 12.2.4 Campos de bits [class.bit]
- Estándar C++14 (ISO/IEC 14882:2014):
-
- 9.6 Campos de bits [class.bit]
- Estándar C++11 (ISO/IEC 14882:2011):
-
- 9.6 Campos de bits [class.bit]
- Estándar C++03 (ISO/IEC 14882:2003):
-
- 9.6 Campos de bits [class.bit]
- Estándar C++98 (ISO/IEC 14882:1998):
-
- 9.6 Campos de bits [class.bit]
Véase también
|
implementa arreglo de bits de longitud constante
(class template) |
|
|
bitset dinámico eficiente en espacio
(class template specialization) |
|
| Bit manipulation (C++20) | utilidades para acceder, manipular y procesar bits individuales y secuencias de bits |
|
C documentation
para
Bit-fields
|
|