operadores manipulacion especiales ejemplos desplazamiento derecha corrimiento bitwise c bit-manipulation padding bitwise-operators
compatible con C89

manipulacion - operadores de bits java



Pregunta C: Relleno de bits en enteros sin signo y operaciones a nivel de bits(C89) (1)

Las operaciones bitwise (como las operaciones aritméticas) operan en valores e ignoran el relleno. La implementación puede o no modificar los bits de relleno (o usarlos internamente, por ejemplo, como bits de paridad), pero el código C portátil nunca podrá detectar esto. Cualquier valor (incluido UINT_MAX ) no incluirá el relleno.

Donde el relleno de enteros puede llevar a problemas es si usa cosas como sizeof (int) * CHAR_BIT y luego intenta usar turnos para acceder a todos estos bits. Si desea ser portátil, use solo caracteres ( unsigned ), enteros de tamaño fijo (una adición de C99) o determine la cantidad de bits de valor programáticamente. Esto se puede hacer en tiempo de compilación con el preprocesador comparando UINT_MAX con potencias de 2 o en tiempo de ejecución mediante operaciones de bits.

editar:

C90 no menciona el relleno de enteros en absoluto, pero por lo que puedo decir, los bits de relleno de enteros anteriores o posteriores ''invisibles'' no deben violar el estándar (no revisé todas las secciones relevantes para asegurarme de que este sea realmente el caso , aunque); allí es probable que haya problemas con el relleno mixto y los bits de valor, como se menciona en el razonamiento de C99, porque de lo contrario, no habría sido necesario cambiar el estándar.

En cuanto al significado de acceso al usuario: los bits de relleno son accesibles en la medida en que siempre puede obtener cualquier bit de foo (incluido el relleno) mediante operaciones de bit en ((unsigned char *)&foo)[…] . Sin embargo, tenga cuidado al modificar los bits de relleno: el resultado no cambiará el valor del entero, pero podría crear una representación de trampa. En el caso de C90, esto está implícitamente sin especificar (como no se menciona en absoluto), en el caso de C99, está definido por la implementación.

Sin embargo, esto no era de lo que trataba la cita racional: la arquitectura citada representa enteros de 32 bits a través de dos enteros de 16 bits. En el caso de tipos sin signo, el entero resultante tiene 32 bits de valor y una precisión de 32; en el caso de los enteros con signo, solo tiene 31 bits de valor y una precisión de 30: uno de los bits de signo de los enteros de 16 bits se utiliza como el bit de signo del entero de 32 bits, el otro se ignora, creando así Un bit de relleno rodeado de bits de valor. Ahora, si accede a un entero con signo de 32 bits como un entero sin signo (que se permite explícitamente y no viola las reglas de aliasing de C99), el bit de relleno se convierte en un bit de valor (accesible por el usuario).

Tengo un montón de código que realiza operaciones bitwise en enteros sin signo. Escribí mi código asumiendo que esas operaciones se realizaban en enteros de ancho fijo sin ningún bit de relleno. Por ejemplo, una matriz de enteros sin signo de 32 bits, de los cuales todos los 32 bits están disponibles para cada entero.

Estoy buscando hacer que mi código sea más portátil y estoy enfocado en asegurarme de que soy compatible con C89 (en este caso). Uno de los problemas que he encontrado son los posibles enteros rellenados. Tomemos este ejemplo extremo, tomado del manual GMP :

Sin embargo, en los sistemas de vectores Cray se puede observar que short e int siempre se almacenan en 8 bytes (y con el tamaño que indica eso) pero que usan solo 32 o 46 bits. La característica de los clavos puede explicar esto, pasando la instancia 8 * sizeof (int) -INT_BIT.

También he leído sobre este tipo de relleno en otros lugares. De hecho, leí un post en SO anoche (perdóname, no tengo el enlace y citaré algo similar de memoria) donde si tienes, digamos, un doble con 60 bits utilizables, los otros 4 podrían puede usarse para relleno y esos bits de relleno podrían servir para algún propósito interno, por lo que no pueden modificarse.


Digamos, por ejemplo, que mi código se compila en una plataforma donde un tipo int sin signo tiene un tamaño de 4 bytes, cada byte es de 8 bits, sin embargo, los 2 bits más significativos son los bits de relleno. ¿Sería UINT_MAX en ese caso 0x3FFFFFFF (1073741823)?

#include <stdio.h> #include <stdlib.h> /* padding bits represented by underscores */ int main( int argc, char **argv ) { unsigned int a = 0x2AAAAAAA; /* __101010101010101010101010101010 */ unsigned int b = 0x15555555; /* __010101010101010101010101010101 */ unsigned int c = a ^ b; /* ?? __111111111111111111111111111111 */ unsigned int d = c << 5; /* ?? __111111111111111111111111100000 */ unsigned int e = d >> 5; /* ?? __000001111111111111111111111111 */ printf( "a: %X/nb: %X/nc: %X/nd: %X/ne: %X/n", a, b, c, d, e ); return 0; }

¿Es seguro XOR dos enteros con bits de relleno?
¿No sería XOR cualesquiera que sean los bits de relleno?
No puedo encontrar este comportamiento cubierto en C89.
además, ¿se garantiza que c var sea 0x3FFFFFFF o si, por ejemplo, los dos bits de relleno estaban ambos en a o b, c sería 0xFFFFFFFF?
misma pregunta con d y e. ¿Estoy manipulando los bits de relleno cambiando? Espero ver esto a continuación, asumiendo 32 bits con los 2 bits más significativos utilizados para el relleno, pero quiero saber si algo como esto está garantizado:

a: 2AAAAAAA b: 15555555 c: 3FFFFFFF d: 3FFFFFE0 e: 01FFFFFF

¿También los bits de relleno son siempre los bits más significativos o podrían ser los bits menos significativos?

Gracias chicos


EDITAR 19/12/2010 5PM EST : Christoph ha respondido a mi pregunta. ¡Gracias!
También pregunté (arriba) si los bits de relleno son siempre los bits más significativos. Esto se cita en la justificación del estándar C99, y la respuesta es no. Estoy jugando seguro y asumiendo lo mismo para C89. Aquí está específicamente lo que dice la lógica de C99 para §6.2.6.2 (Representación de tipos de enteros):

Los bits de relleno son accesibles para el usuario en un tipo entero sin signo. Por ejemplo, supongamos que una máquina utiliza un par de cortos de 16 bits (cada uno con su propio bit de signo) para formar un int de 32 bits y el bit de signo del cortocircuito inferior se ignora cuando se usa en este int de 32 bits. Luego, como un int con signo de 32 bits, hay un bit de relleno (en medio de los 32 bits) que se ignora al determinar el valor del int con signo de 32 bits. Pero, si este elemento de 32 bits se trata como un int sin signo de 32 bits, entonces ese bit de relleno es visible para el programa del usuario. Se le dijo al comité de C que hay una máquina que funciona de esta manera, y esa es una de las razones por las cuales los bits de relleno se agregaron a C99.

Las notas de pie de página 44 y 45 mencionan que los bits de paridad pueden ser bits de relleno. El comité no conoce ninguna máquina con bits de paridad accesibles por el usuario dentro de un entero. Por lo tanto, el comité no tiene conocimiento de ninguna máquina que trate los bits de paridad como bits de relleno.


EDICIÓN 12/28/2010 3PM EST : Encontré una interesante discusión sobre comp.lang.c de hace unos meses.
Efectos de operador bitwise en bits de relleno (VelocityReviews reader)
Efectos del operador de Bitwise en los bits de relleno (enlace alternativo de Grupos de Google)
Un punto hecho por Dietmar que me pareció interesante:

Notemos que los bits de relleno no son necesarios para la existencia de representaciones de trampas; También lo harían las combinaciones de bits de valor que no representan un valor del tipo de objeto.