operaciones nivel manipulacion manejo invertir ejercicios ejemplos desplazamiento c++ c integer language-lawyer data-representation

c++ - nivel - manipulacion de bits pdf



¿Qué dicen los estándares de C y C++ sobre la representación y manipulación de enteros a nivel de bits? (8)

Sé que los estándares C y C ++ no dictan una representación particular para los números (podría ser el complemento de dos, signo y magnitud, etc.). Pero no conozco los estándares lo suficiente (y no podría encontrarlos si están establecidos) para saber si existen restricciones / garantías / representaciones reservadas particulares cuando se trabaja con bits. Particularmente:

  1. Si todos los bits en un tipo entero son cero, ¿el entero como entero representa cero?
  2. Si cualquier bit en un tipo de entero es uno, ¿el entero en su totalidad representa un no cero? (Si se trata de un "sí", entonces se restringirán adicionalmente algunas representaciones como signo-y-magnitud)
  3. ¿Hay una forma garantizada de verificar si algún bit no está configurado?
  4. ¿Hay una forma garantizada de comprobar si se establece algún bit? (Los tipos # 3 y # 4 dependen de # 1 y # 2, porque sé cómo configurar, por ejemplo, el quinto bit (ver # 5) en alguna variable x , y me gustaría marcar una variable y para ver si el quinto bit es 1, me gustaría saber si if (x & y) funcionará (porque, según tengo entendido, esto depende del valor de la representación y no de si ese bit no es realmente 1 o 0)
  5. ¿Hay una forma garantizada de establecer los bits más a la izquierda y / o a la derecha? (Al menos una forma más simple que tomar un char c con todos los bits verdaderos (establecido por c = c | ~c ) y hacer c = c << (CHAR_BIT - 1) para configurar el bit alto y c = c ^ (c << 1) para el bit bajo, asumiendo que no estoy haciendo ninguna suposición que no debería ser, dadas estas preguntas)
  6. Si la respuesta al # 1 es "no", ¿cómo podría uno iterar sobre los bits en un tipo entero y verificar si cada uno era un 1 o un 0?

Supongo que mi pregunta general es: ¿existen restricciones / garantías / representaciones reservadas hechas por los estándares C y C ++ con respecto a bits y enteros, a pesar del hecho de que la representación de un número entero no es obligatoria (y si los estándares C y C ++ difieren a este respecto?) , cual es su diferencia?

Se me ocurrieron estas preguntas mientras hacía mi tarea, que me obligaba a manipular un poco (tenga en cuenta que no son preguntas de mi tarea, son mucho más "abstractas").

Edición: En cuanto a lo que me refiero a "bits", me refiero a bits de "formación de valor" y no incluyo bits de "relleno".


P: Si cualquier bit en un tipo de entero es uno, ¿el entero en su totalidad representa un no cero? (Si se trata de un "sí", entonces se restringirán adicionalmente algunas representaciones como signo-y-magnitud)

No. Los estándares para C y C ++ no descartan la magnitud firmada o el complemento de uno, los cuales tienen +0 y -0. Mientras que +0 y -0 tienen que comparar iguales, pero no tienen que tener la misma representación.

Buena suerte para encontrar una máquina hoy en día que use una magnitud con signo o el complemento de uno.


Si todos los bits en un tipo entero son cero, ¿el entero como entero representa cero?

Edición : ya que ahora ha aclarado que no le preocupan los bits de relleno, la respuesta a esto es en realidad "sí". Pero os dejo el original:

No necesariamente, podría ser una representación trampa. Ver C99 6.2.6.1:

Para tipos de enteros sin signo distintos de los caracteres sin signo, los bits de la representación del objeto se dividirán en dos grupos: bits de valor y bits de relleno (no es necesario que haya ninguno de estos últimos)

La presencia de bits de relleno permite la posibilidad de que todo 0 sea una representación de captura . (Como lo señaló Keith Thompson en el comentario a continuación, el C11 más reciente hace explícito que dicha representación no es una representación trampa).

y

Los valores de cualquier bit de relleno no están especificados.

y

44) Algunas combinaciones de bits de relleno podrían generar representaciones de trampas

Si restringe la pregunta para que valore y firme bits, la respuesta es sí, debido a 6.2.6.2:

Si hay N bits de valor, cada bit representará una potencia diferente de 2 entre 1 y 2 N −1, de modo que los objetos de ese tipo podrán representar valores de 0 a 2 N - 1 usando una representación binaria pura; Esto se conocerá como la representación del valor.

y

Si el bit de signo es cero, no afectará el valor resultante.

Si cualquier bit en un tipo de entero es uno, ¿el entero en su totalidad representa un no cero? (Si se trata de un "sí", entonces se restringirán adicionalmente algunas representaciones como signo-y-magnitud)

No necesariamente, y de hecho la signatura y la magnitud se admite explícitamente en 6.2.6.2.

¿Hay una forma garantizada de verificar si algún bit no está configurado?

Si no le importa el relleno y la firma de bits, podría comparar con 0, pero esto no funcionaría con una representación de complemento de 1 (que está permitida) ya que todos los bits 0 y todos los bits 1 representan el valor 0.

De lo contrario, puede leer el valor de cada byte a través de un unsigned char * y comparar el resultado con 0:

Los valores almacenados en campos de bits sin firmar y objetos de tipo unsigned char se representarán utilizando una notación binaria pura

Si desea verificar un bit de valor específico, puede construir una máscara de bits adecuada utilizando (1u << n), pero esto no necesariamente le permitirá inspeccionar el bit de signo .

¿Hay una forma garantizada de comprobar si se establece algún bit?

La respuesta es esencialmente la misma que en la pregunta anterior.

¿Hay una forma garantizada de establecer los bits más a la izquierda y / o a la derecha?

¿Quieres decir el bit de valor más a la izquierda? Puede contar los bits en INT_MAX o UINT_MAX o su equivalente, dependiendo del tipo, y usarlo para construir un valor (a través de 1 << n ) con el cual OR el valor original.

Si la respuesta al # 1 es "no", ¿cómo podría uno iterar sobre los bits en un tipo entero y verificar si cada uno era un 1 o un 0?

Puede hacerlo usando una máscara de bits que dejó desplazado repetidamente, pero solo puede verificar los bits de valor de esta manera y no el bit de signo .


(1) Si todos los bits en un tipo de entero son cero, ¿el entero como entero representa cero?

Sí, el patrón de bits que consta de todos los ceros siempre representa 0:

Las representaciones de los tipos integrales definirán valores mediante el uso de un sistema de numeración binaria pura. 49 [§3.9.1 / 7]

49 Una representación posicional para enteros que usa los dígitos binarios 0 y 1, en la que los valores representados por bits sucesivos son aditivos, comienzan con 1 y se multiplican por la potencia integral sucesiva de 2, excepto quizás para el bit con la posición más alta.

(2) Si cualquier bit en un tipo de entero es uno, ¿el entero en su totalidad representa un no cero? (Si se trata de un "sí", entonces se restringirán adicionalmente algunas representaciones como signo-y-magnitud)

No. De hecho, la magnitud firmada está específicamente permitida:

[ Ejemplo: esta Norma Internacional permite el complemento de 2, el complemento de 1 y las representaciones de magnitud con signo para tipos integrales. —En el ejemplo ] [§3.9.1 / 7]

(3) ¿Hay una forma garantizada de verificar si algún bit no está establecido?

Creo que la respuesta a esto es "no", si considera los tipos firmados. Es equivalente a la prueba de igualdad con un patrón de bits de todos, lo que solo es posible si tiene una forma de producir un número con signo con el patrón de bits de todos. Para un número sin firmar, esta representación está garantizada, pero la conversión de sin firmar a firmada no está definida si el número no se puede representar:

Si el tipo de destino está firmado, el valor no cambia si se puede representar en el tipo de destino (y el ancho del campo de bits); de lo contrario, el valor está definido por la implementación. [§4.7 / 3]

(4) ¿Hay una forma garantizada de verificar si se establece algún bit?

No lo creo, porque la magnitud con signo está permitida, 0 se compararía igual a −0. Pero debería ser posible con números sin firmar.

(5) ¿Hay una forma garantizada de establecer los bits más a la izquierda y / o a la derecha?

Nuevamente, creo que la respuesta es "sí" para los números sin firmar, pero "no" para los números firmados. Los turnos no están definidos para números con signo negativo:

De lo contrario, si E1 tiene un tipo con signo y un valor no negativo, y E1 × 2 E2 se puede representar en el tipo de resultado, entonces ese es el valor resultante; de lo contrario, el comportamiento es indefinido. [§5.8 / 2]


Para las manipulaciones de bits, puede hacer una estructura con 8 campos de bit sin firmar y dejar que el puntero de esa estructura apunte a su carácter. De esa manera puedes acceder fácilmente a cada bit. Pero el compilador probablemente hará enmascaramiento debajo del capó, por lo que creo que es solo una forma más limpia para el programador. Debe verificar que su compilador no cambie el orden de los campos al hacer esto.

yourstruct* pChar=(yourstruct*)(&c) pChar.Bit7=1;


Permítame advertirlo diciendo que me dirijo a C y C ++ en general (p. Ej., C90 e inferior, MS Visual C ++, etc.): el "mayor denominador común" (en comparación con el "estándar" más reciente / mayor de cx11).

P: Si todos los bits en un tipo entero son cero, ¿el entero como entero representa cero?

A: si

P: Si cualquier bit en un tipo de entero es uno, ¿el entero en su totalidad representa un no cero? (Si se trata de un "sí", entonces se restringirán adicionalmente algunas representaciones como signo-y-magnitud)

A: si Esto incluye el bit de signo, para un int firmado. Francamente no estoy familiarizado con la "magnitud"

P: ¿Hay una forma garantizada de verificar si algún bit no está establecido?

R: "Y''ing" una máscara de bits siempre está garantizada.

P: ¿Hay una forma garantizada de verificar si se establece algún bit?

R: Una vez más, "y" una máscara de bits siempre está garantizada.

P: ¿Hay una forma garantizada de establecer los bits más a la izquierda y / o a la derecha?

R: Creo que siempre debería tener un "MAX_INT" disponible para todas las implementaciones / todas las arquitecturas para determinar el bit más a la izquierda.

Estoy preparado para ser incendiado ... pero creo que lo anterior es correcto. Y espero que ayude.

EN MI HUMILDE OPINIÓN...


Si quiere que su cerebro explote, considere esto: si interpreta un int o un largo o un largo como una matriz de caracteres sin signo (que es lo más razonable si quiere ver todos los bits), sabe que el orden de los bytes no está definido, por ejemplo, "bigendian" frente a "littleendian". Todos (con suerte) lo sabemos.

Pero es peor: cada bit de un int podría almacenarse en cualquiera de los bits de la matriz de caracteres. ¡Así que hay 32! formas en que los bits de un entero de 32 bits se pueden asignar a una matriz de cuatro caracteres sin signo de 8 bits mediante una implementación realmente extraña. Afortunadamente, no me he encontrado con más de dos maneras (y conozco una orden más en una computadora real).


Utiliza el término "todos los bits" repetidamente, pero no aclara a qué "todos los bits" se refiere. La representación de objetos de tipos enteros en C / C ++ puede incluir bits formadores de valor y bits de relleno . El único tipo de entero que se garantiza que no tiene bits de relleno es [signed/unsigned] char .

El lenguaje siempre garantizó que si todos los bits formadores de valor son cero, entonces el valor entero representado también es cero.

En cuanto a los bits de relleno , las cosas son un poco más complicadas. La especificación original del lenguaje C (C89 / 90, así como la C99 original) no garantizaba que el establecimiento de todos los bits de objeto a cero produjera una representación entera válida. Podría haber producido una representación de trampa no válida. Es decir, en la C original (e incluso en C99 al principio) utilizando memset(..., 0, ...) en tipos de enteros no garantizó que los objetos reciban valores de cero válidos (con la excepción de [signed/unsigned] char ). Esto se modificó en las especificaciones posteriores, concretamente en una de las correcciones técnicas para C99. Ahora se requiere que el patrón de bits de todo cero en un objeto entero (que involucre a todos los bits, incluidos los de relleno) represente un valor cero válido.

Es decir, en la C moderna es legal usar memset(..., 0, ...) para establecer cualquier objeto entero en cero, pero se convirtió en legal solo después de C99.


Ya tienes algunas respuestas sobre la representación de valores enteros. Existe una manera exacta de garantizar todos los bits individuales de cualquier objeto representado en la memoria: verlo como una matriz de caracteres unsigned char . Este es el único tipo integral que no tiene bits de relleno y se garantiza que no tiene representación de captura. Por lo tanto, la conversión de un puntero de tipo T* a su objeto a un unsigned char* siempre funcionará, siempre y cuando solo acceda a los primeros bytes de sizeof(T) . De esta forma, puede inspeccionar y configurar todos los bytes (y, por lo tanto, bits) a su gusto.

Si está interesado en obtener más detalles, aquí he escrito algo sobre la anatomía de los tipos enteros en C. C ++ podría diferir un poco de eso, en particular el punteo de tipos a través de la union como se describe allí no parece estar bien definido en C ++ .