c++: ¿el carácter sin firmar que se desplaza hacia la derecha se está llenando de unos?

CorePress2024-01-25  11

En mi sistema, (carácter sin firmar) -1 es (esperadamente para caracteres de 8 bits) 1111 1111 en binario (255 decimal).

Del mismo modo, (carácter sin firmar) -1 >> 1 es como se esperaba 0111 1111. La izquierda se llenó con un cero.

~((unsigned char) -1 >> 1) es 1000 0000 como se esperaba.

Ahora quiero generar el carácter sin firmar 0010 0000, por ejemplo.

Probé ~((unsigned char) -1 >> 1) >> 2, pero esto genera 1110 0000.... ¿qué? ¿Por qué la izquierda se está llenando de unos de repente?

¿Cómo puedo generar un carácter sin firmar con el enésimo bit (desde la izquierda) habilitado?

Me gustaría

n   unsigned char
0   1000 0000
1   0100 0000
2   0010 0000
3   0001 0000
... 
7   0000 0001

Por el momento, ~((unsigned char) -1 >> 1) >> n me esta dando

n   unsigned char
0   1000 0000
1   1100 0000
2   1110 0000
3   1111 0000
... 
7   1111 1111

Este problema existe para uint8_t, uint16_t, pero ya no ocurreen uint32_t y mayores.

2

Sugerencia: int puede representar todos los valores de un carácter sin firmar.

-EOF

27/03/2021 a las 15:07

1

No etiquete C y C++ excepto cuando pregunte sobre diferencias o interacciones entre los lenguajes. Son idiomas diferentes, muchas veces tienen respuesta diferente.Se refiere incluso a preguntas aparentemente simples y, a menudo, las responden diferentes personas. Esto crea confusión cuando una persona responde por uno pero otra busca una respuesta por el otro.

- Eric Postpischil

27/03/2021 a las 15:30



------------------------------------

Debido a las promociones de números enteros, unsigned char se promueve a int cuando se realiza prácticamente cualquier operación con el valor.

Cuando se desplaza hacia la derecha, el operando izquierdo sufre promociones de números enteros y el carácter sin signo se convierte en int. El valor de la expresión será el del operando izquierdo después de las promociones; por lo tanto, el resultado de ((unsigned char) -1 >> 1) tiene el valor 127, de tipo int. Si ~ (int)127 obtendrás un int con el bit de signo establecido; desplazar ese derecho tendrá un comportamiento definido por la implementación.

La solución es agregar un molde alrededor del exterior ~:

(unsigned char)~((unsigned char) -1 >> 1) >> 2

O alternativamente, & el valor con 0xFF:

(~((unsigned char) -1 >> 1) >> 2) & 0xFF

En cuanto a configurar el enésimo bit desde la izquierda del carácter sin firmar, la mejor solución es *desplazar a la izquierda 1U a la posición, como lo muestra Allan Wind.

1

@EricPostpischil cierto.

- Antti Haapala - Слава Україні

27/03/2021 a las 15:31



------------------------------------

Otra forma de configurar el enésimo bit (desde la izquierda):

1 << (CHAR_BIT - n - 1)

0



------------------------------------

Puedes aprovechar std::numeric_limits<T>::digits para crear un código menos confuso y flexible:

    unsigned char data=0;
    
    const uint8_t sizeBit=std::numeric_limits<decltype(data)>::digits;
    for(uint8_t n=0;n<sizeBit;n++) {
        data = 1 << (sizeBit - (n+1));
        std::bitset<sizeBit> x(data);
        std::cout << x << '\n';
    }

Impresiones:

10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare