¿Por qué un booleano tiene 1 byte y no 1 bit de tamaño?

127

En C ++,

  • ¿Por qué un booleano tiene 1 byte y no 1 bit de tamaño?
  • ¿Por qué no hay tipos como enteros de 4 o 2 bits?

Me estoy perdiendo las cosas anteriores cuando escribo un emulador para una CPU

Asm
fuente
10
En C ++ puede "empaquetar" los datos utilizando campos de bits. struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };. La mayoría de los compiladores asignarán un completo unsigned int, sin embargo, se ocupan de los cambios de bits por sí mismos cuando lees / escribes. También se ocupan solos de las operaciones de módulo. Es un unsigned small : 4atributo que tiene un valor entre 0 y 15, y cuando debería llegar a 16, no sobrescribirá el bit anterior :)
Matthieu M.

Respuestas:

208

Porque la CPU no puede abordar nada más pequeño que un byte.

Paul Tomblin
fuente
10
Maldición, ahora eso es incómodo Señor
Asm
31
En realidad, los cuatro x86 instrucciones bt, bts, btry btc pueden direccionar bits individuales!
fredoverflow
11
Creo que btaborda un desplazamiento de bytes y luego prueba el bit en un desplazamiento dado, independientemente, al especificar una dirección que vaya en bytes ... los literales de desplazamiento de bits se volverían un poco prolíficos (disculpe el juego de palabras).
user7116
2
@six: puede cargar el comienzo de una matriz en un registro y luego el relativo "desplazamiento de bits" en un segundo. El desplazamiento de bits no se limita a "dentro de un byte", puede ser cualquier número de 32 bits.
fredoverflow
44
Pues sí y no. Tenemos campos de bits, y podríamos tener un puntero de campo de bits, es decir, dirección + número de bit. Obviamente, dicho puntero no sería convertible a vacío * debido al requisito de almacenamiento adicional para el número de bit.
Maxim Egorushkin
32

De Wikipedia :

Históricamente, un byte era el número de bits utilizados para codificar un solo carácter de texto en una computadora y es por esta razón el elemento direccionable básico en muchas arquitecturas de computadora.

Entonces, el byte es la unidad direccionable básica , debajo de la cual la arquitectura de la computadora no puede abordar. Y dado que (probablemente) no existen computadoras que admitan byte de 4 bits, no tiene 4 bits, bool etc.

Sin embargo, si puede diseñar una arquitectura de este tipo que pueda abordar 4 bits como unidad direccionable básica, entonces tendrá un booltamaño de 4 bits, ¡solo en esa computadora!

Nawaz
fuente
44
"entonces tendrá un tamaño int de 4 bits, solo en esa computadora" - no, no lo hará, porque el estándar prohíbe que CHAR_BIT sea menor que 8. Si la unidad direccionable en la arquitectura es menor que 8 bits, entonces un La implementación de C ++ solo tendrá que presentar un modelo de memoria que sea diferente del modelo de memoria del hardware subyacente.
Steve Jessop
@ Steve: Uy ... Pasé por alto eso. Eliminado inty charde mi publicación.
Nawaz
1
tampoco puede tener un 4 bits bool, porque chares la unidad direccionable más pequeña en C ++ , independientemente de lo que la arquitectura pueda abordar con sus propios códigos de operación. sizeof(bool)debe tener un valor de al menos 1, y los boolobjetos adyacentes deben tener sus propias direcciones en C ++ , por lo que la implementación solo debe hacerlos más grandes y desperdiciar memoria. Es por eso que los campos de bits existen como un caso especial: no se requiere que los miembros de campo de bits de una estructura sean direccionables por separado, por lo que pueden ser más pequeños que un char(aunque toda la estructura aún no puede serlo).
Steve Jessop
@ Steve Jessop: eso parece interesante. ¿podría darme la referencia de la especificación del lenguaje donde dice que chares la unidad direccionable más pequeña en C ++?
Nawaz
3
la declaración específica más cercana es probablemente 3.9 / 4: "La representación de objeto de un objeto de tipo T es la secuencia de N objetos de caracteres sin signo tomados por el objeto de tipo T, donde N es igual a sizeof (T)". Obviamente sizeof(bool)no puede ser 0.5 :-) Supongo que una implementación podría proporcionar legalmente punteros de subbytes como una extensión, pero los objetos "ordinarios" como bool, asignados de manera ordinaria, tienen que hacer lo que dice el estándar.
Steve Jessop
12

La respuesta más fácil es; es porque la CPU direcciona la memoria en bytes y no en bits, y las operaciones bit a bit son muy lentas.

Sin embargo, es posible utilizar la asignación de tamaño de bits en C ++. Hay especialización std :: vector para vectores de bits, y también estructuras que toman entradas de tamaño de bit.

sukru
fuente
1
No estoy seguro de estar de acuerdo en que las operaciones bit a bit son lentas. ands, nots, xors, etc.son muy rápidos. Por lo general, la implementación de las operaciones bit a bit es lenta. A nivel de máquina son bastante rápidos. Ramificación ... ahora eso es lento.
Hogan
3
Solo para dejarlo más claro, si crea un vector de booleanos y le pone 24 booleanos, tomará solo 3 bytes (3 * 8). Si coloca otro booleano, tomará otro byte. Sin embargo, si empuja otro booleano, no tomará bytes adicionales porque usa los bits "libres" en el último byte
Pedro Loureiro
sí, también dudo que las operaciones de mordisco sean lentas :)
Pedro Loureiro
Los vectores de bits no crean asignaciones de tamaño de bits. crean asignaciones de tamaño de byte. No es posible asignar un solo bit.
John Dibling
1
La lectura de un solo bit en un vector de bits requiere tres operaciones: shift, y, y otro shift nuevamente. Escribir es dos. Mientras que se puede acceder a bytes individuales con uno solo.
sukru
7

En los viejos tiempos, cuando tenía que caminar a la escuela en una tormenta de nieve, cuesta arriba en ambos sentidos, y el almuerzo era cualquier animal que pudiéramos rastrear en el bosque detrás de la escuela y matar con nuestras propias manos, las computadoras tenían mucha menos memoria disponible que hoy. La primera computadora que utilicé tenía 6K de RAM. No 6 megabytes, no 6 gigabytes, 6 kilobytes. En ese entorno, tenía mucho sentido agrupar tantos booleanos en un int como pudiera, por lo que usamos regularmente operaciones para eliminarlos y colocarlos.

Hoy en día, cuando las personas se burlan de ti por tener solo 1 GB de RAM, y el único lugar donde puedes encontrar un disco duro con menos de 200 GB es en una tienda de antigüedades, simplemente no vale la pena empacar pedazos.

Arrendajo
fuente
Excepto cuando se trata de banderas. Cosas como establecer múltiples opciones en algo ... por ejemplo. 00000001 + 00000100 = 00000101.
Armstrongest
@ Atomix: ya casi nunca hago esto. Si necesito dos banderas, creo dos campos booleanos. Solía ​​escribir código donde empacaba banderas como esa y luego escribía "if flags & 0x110! = 0 then" o similar, pero esto es críptico y en estos días generalmente hago campos separados y escribo "if fooFlag || barFlag "en su lugar. No descartaría la posibilidad de casos en los que empaquetar banderas como esa sea mejor por alguna razón, pero ya no es necesario guardar memoria como solía ser.
Jay
2
En realidad, es bastante digno de su molestia de empacar los bits, si desea que su cálculo sea rápido - en esa gran cantidad de datos que almacena en la memoria. Empacar booleanos no es solo para un almacenamiento más pequeño: significa que puede leer sus matrices de entrada booleanas 8 veces más rápido (en términos de ancho de banda) como cuando están desempaquetadas, y eso a menudo es bastante significativo. Además, puede usar operaciones de bit, como popc (conteo de población) que acelera su trabajo en la CPU.
einpoklum
2
Con lo que trabajas todos los días es con una cantidad realmente enorme de booleanos: DBMS, aprendizaje automático, simulaciones científicas y muchas otras cosas. Y, solo trabajar en ellos significa copiarlos, de la memoria al caché. Un millón de bools no es nada, piensa miles de millones.
einpoklum
1
@PeterCordes Sí, absolutamente, si tuviera un conjunto de booleanos que lógicamente fueran la "misma idea", de modo que naturalmente los considero como una "matriz" en algún sentido, y si voy a enmascararlos o filtrarlos o de lo contrario, realice operaciones bit a bit en ellos, luego empaquetarlos en bytes podría tener sentido. Como dije antes, me cuesta pensar en la última vez que trabajé en una aplicación en la que se aplicaban esas condiciones, pero usted da un par de buenos ejemplos, y estoy seguro de que con un poco de imaginación uno podría pensar en otros.
Jay
6

Podría tener bools de 1 bit y entradas de 4 y 2 bits. Pero eso daría lugar a un conjunto de instrucciones extraño sin ganancia de rendimiento porque es una forma poco natural de ver la arquitectura. En realidad, tiene sentido "desperdiciar" una mejor parte de un byte en lugar de intentar recuperar esos datos no utilizados.

La única aplicación que se molesta en empacar varios bools en un solo byte, en mi experiencia, es Sql Server.

Paul Sasik
fuente
5

Puede usar campos de bits para obtener enteros de sub tamaño.

struct X
{
    int   val:4;   // 4 bit int.
};

Aunque generalmente se usa para asignar estructuras a los patrones de bits esperados del hardware exacto:

struct SomThing   // 1 byte value (on a system where 8 bits is a byte
{
    int   p1:4;   // 4 bit field
    int   p2:3;   // 3 bit field
    int   p3:1;   // 1 bit
};
Martin York
fuente
5

Porque un byte es la unidad direccionable más pequeña del idioma.

Pero puede hacer que bool tome 1 bit, por ejemplo, si tiene un montón de ellos, por ejemplo. en una estructura, como esta:

struct A
{
  bool a:1, b:1, c:1, d:1, e:1;
};
bratao
fuente
2

boolpuede ser de un byte, el tamaño direccionable más pequeño de la CPU, o puede ser más grande. No es inusual tener boolque ser del tamaño de intpara fines de rendimiento. Si para fines específicos (por ejemplo, simulación de hardware) necesita un tipo con N bits, puede encontrar una biblioteca para eso (por ejemplo, la biblioteca GBL tiene BitSet<N>clase). Si le preocupa el tamaño de bool(probablemente tenga un contenedor grande), puede empacar pedazos usted mismo, o usarlo std::vector<bool>para hacerlo por usted (tenga cuidado con esto último, ya que no satisface los requisitos del contenedor).

Gene Bushuyev
fuente
2

Piense en cómo implementaría esto en su nivel de emulador ...

bool a[10] = {false};

bool &rbool = a[3];
bool *pbool = a + 3;

assert(pbool == &rbool);
rbool = true;
assert(*pbool);
*pbool = false;
assert(!rbool);
franji1
fuente
2

Porque, en general, la CPU asigna memoria con 1 byte como unidad básica, aunque algunas CPU como MIPS usan una palabra de 4 bytes.

Sin embargo, las vectorofertas boolde una manera especial, con vector<bool>un bit por cada bool se asigna.

Ryan Li
fuente
1
Creo que incluso la CPU MIPS le dará acceso a un byte individual, aunque hay una penalización de rendimiento.
Paul Tomblin
@Paul: Sí, tienes razón, pero generalmente las palabras específicas lw/ swson mucho más utilizadas.
Ryan Li
No sé acerca de MIPS, pero la arquitectura IA-64 solo permite el acceso en el límite de 64 bits.
Gene Bushuyev
0

El byte es la unidad más pequeña de almacenamiento de datos digitales de una computadora. En una computadora, la RAM tiene millones de bytes y cualquiera de ellos tiene una dirección. Si tuviera una dirección por cada bit, una computadora podría administrar 8 veces menos RAM de lo que puede.

Más información: Wikipedia

Francesco Pasa
fuente
0

Incluso cuando el tamaño mínimo posible es de 1 byte, puede tener 8 bits de información booleana en 1 byte:

http://en.wikipedia.org/wiki/Bit_array

El lenguaje Julia tiene BitArray, por ejemplo, y leí sobre implementaciones de C ++.

Diego Javier Zea
fuente