La operación bit a bit en char da un resultado de 32 bits

He estado escribiendo un programa en C para mover los primeros 4 bits de un carácter al final y los últimos 4 al principio. Para la mayoría de los valores funciona normalmente, así como la operación inversa, pero para algunos valores, como 8, x, y, z, da como resultado un valor de 32 bits. Valores comprobados mediante la impresión del valor hexadecimal de la variable. ¿Alguien puede explicar por qué sucede esto?

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char o, f,a=15;
    scanf("%c",&o);
    printf("o= %d\n",o);
    f=o&a;
    o=o>>4;
    printf("o= %d",o);
    o=o|(f<<4);
    printf("o= %x, size=%d\n",o,sizeof(o));
    f=o&a;
    o=o>>4;
    printf("o= %d",o);
    o=o|(f<<4);
    printf("o= %x, size=%d\n",o,sizeof(o));
    return 0;
}

preguntado el 12 de junio de 12 a las 18:06

sizeof(o) es una de esas cosas que nunca cambiarán -

@K-ballo, sin embargo, es una buena práctica ser consistente; todos los demás tamaños requieren este operador, por lo que el tipo de o nunca cambia, no te hará pasar un mal rato. -

@ H2CO3: tengo la impresión de que el OP está imprimiendo el resultado de sizeof(o) para ver si el tipo, y por lo tanto el tamaño, de o cambió. -

Sí, pero no veo por qué eso está relacionado con mi comentario. Obviamente, necesita observar el tamaño si lo imprime, y tal vez no use este código solo con caracteres, sino posiblemente con otros tipos de datos. -

@H2CO3: C está tipado estáticamente. Impresión sizeof(o) dos veces en el mismo ámbito es redundante, independientemente de para qué se use el código. -

4 Respuestas

Pasando (Paso) o como argumento para printf() resulta en una conversión automática a int, que aparentemente es de 32 bits en su sistema. La conversión automática usa extensión de signo, por lo que si el bit 7 en o está establecido, se establecerán los bits 8-31 en el resultado convertido, lo que explicará lo que está viendo.

Podrías usar unsigned char en lugar de char para evitar esto. o pasar o & 0xff a printf().

Respondido el 12 de junio de 12 a las 18:06

@coste y flete: %hhx espera un unsigned char argumento. El estándar parece hacer que pasar un valor negativo sea un comportamiento indefinido, aunque no estoy seguro de que esa fuera la intención. - R .. GitHub DEJA DE AYUDAR A ICE

Intente declarar sus variables como unsigned char. Obtiene una extensión de signo de la parte superior.

Respondido el 12 de junio de 12 a las 18:06

Perdón por no mencionar esto en la pregunta, pero ya sé cómo solucionarlo. Lo que realmente estoy preguntando es por qué sucede esto. Gracias por la respuesta, sin embargo. - Dumitru

Un char dado como argumento para printf (o cualquier función variable, o cualquier función sin prototipo) se promociona a int. Si char está firmado en su plataforma y el valor pasado es negativo, el signo se extiende.

Respondido el 12 de junio de 12 a las 18:06

Sus valores se imprimen como valores de 32 bits porque sus especificadores de formato %x les digas printf para imprimir el valor como un unsigned int. Para imprimirlo como un unsigned char, necesita el especificador de formato %hhx con hh modificador de longitud Si los valores son positivos, eso no hace ninguna diferencia para la salida impresa, pero para los números negativos sí porque tienen el conjunto de bits más significativo.

Para lo siguiente, explicando cómo surgen los valores negativos en ese código, asumo CHAR_BIT == 8 y representación de complemento a dos para enteros negativos.

Para los turnos, el valor de o es ascendido a int. Si se estableció el cuarto bit menos significativo del valor original (si (o & 8) != 0), después del primer intercambio de los nibbles, la parte más significativa de o Está establecido. Si char está firmado por defecto en su plataforma, eso significa que el resultado es negativo. Para el segundo cambio de nibble, el valor de o es nuevamente ascendido a int, resultando en un valor negativo. El desplazamiento a la derecha de los valores negativos está definido por la implementación, por lo que

o=o>>4;

no es portátil en ese caso (aunque, en la práctica, todas las implementaciones usan un desplazamiento aritmético a la derecha [con extensión de signo] o un desplazamiento lógico a la derecha [desplazamiento en ceros desde la izquierda]).

En implementaciones que hacen un cambio aritmético en enteros negativos, los cuatro bits más significativos de o todo estará listo, así que

o=o|(f<<4);

ya no cambia el valor.

La única forma de arreglar el código de forma portátil para obtener el comportamiento deseado es declarar o como una unsigned char como lo sugiere Ned. Entonces todos los valores son positivos y el comportamiento de los turnos está bien definido y coincide con sus expectativas.

Respondido el 12 de junio de 12 a las 19:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.