Cálculo de rangos de tipos de datos en C

Estoy trabajando en la segunda edición de K&R, y no puedo entender por qué estoy obteniendo un resultado determinado. El problema que estoy resolviendo es calcular los límites superior e inferior para los tipos de datos. Específicamente:

“Escriba un progtwig para determinar los rangos de las variables char, short, int y long, con signo y sin signo, imprimiendo los valores apropiados de los encabezados estándar y mediante el cálculo directo. Más difícil si los calcula: determine los rangos de las distintas variables flotantes. tipos de puntos “.

Aprendí sobre los operadores de bitwise y el complemento de dos, y tengo una solución que creo que debería funcionar para los tipos de datos firmados, pero en cambio, funciona para los tipos de datos no firmados que no tienen ningún sentido para mí. Aquí está el código:

#include  main() { signed int i; i = ~0; i >>= 1; printf("Upper limit: %d\n", i); printf("Lower limit: %d\n", -i -1); } 

Esto dará como resultado que se imprima -1 para el límite superior y que se imprima 0 para el límite inferior. Sin embargo, si cambio i por un int sin firmar, obtengo el resultado que esperaba (2147483647 y -2147483648). No puedo entender esto, porque entiendo que un int sin signo nunca puede ser menor que 0, y un int firmado debería funcionar con estos operadores de bit a bit, es decir, si es un sistema de 32 bit,

 ~0 == 11111111111111111111111111111111 

y

 ~0 >> 1 == 011111111111111111111111111111111, or 2147483647. 

¿Alguna idea de dónde voy mal?

Salida:

  1. Nota:
    “En la expresión i >>= 1 , un valor negativo se desplaza hacia la derecha. El estándar C dice que esta es una operación definida por la implementación, y muchas implementaciones la definen como un cambio aritmético. En un cambio aritmético, el bit más significativo no se modifica (mantiene MSB (bit con signo) = 1 ) “.

    (Puede leer: Los números negativos que se desplazan a la derecha en C y que >> depende del comstackdor, ya sea que se modifiquen o no se modifiquen, pero probablemente en su caso se trate de un Cambio aritmético).

    Por esta razón después del código:

      i = ~0; i >>= 1; 

    i queda ~0 . que está en binario == 11111111111111111111111111111111 .

    Y porque ~0 == 11111111111111111111111111111111 es == 2’c complemento de 1 que es -1 .

    Por lo tanto, cuando imprime con la cadena de formato %d se imprime -1 . Debe usar %u para imprimir el valor máximo sin signo que es == ~0 .

    Importante tener en cuenta aquí:

    §6.2.6.2 Idioma 45 , © ISO / IEC ISO / IEC 9899: 201x

    (complemento de uno). ¿Cuál de estos se aplica a la implementation-defined , como si el valor con el bit de signo 1 y todos los bits de valor cero (para los dos primeros), o con el bit de signo y todos los bits de valor 1 (para el complemento de unos), es una representación de trampa? o un valor normal. En el caso de signo y magnitud y el complemento de unos, si esta representación es un valor normal, se llama cero negativo.

    Su comprensión de que:

    ~0 >> 1 == 011111111111111111111111111111111 es incorrecto! (Puede ser pero no está sucediendo en su sistema, según la salida)

    ~0 >> 1 == 111111111111111111111111111111111 , observe que MSB (bit con signo) es 1 .

    Para turnos sin firmar, intente lo siguiente:

    ~0U >> 1 == 011111111111111111111111111111111

    Observe el sufijo U para sin firmar.

  2. Segunda impresión :
    Porque i es -1 , entonces en la segunda expresión -i - 1 == - (-1) - 1 == 1 - 1 == 0 entonces la salida es cero: 0 .

utilizando %d usted trata su valor como signed para continuar con printf .

puedes usar %u lugar.

adicional

Como Magn3s1um señaló, no es necesario que especifique signed o unsigned para su tarea particular. printf hará todo el trabajo por usted.

Su comstackdor implementa >> como cambio aritmético. Por lo tanto, el MSB mantiene su valor de 1 y el cambio no hace nada.

Es decir, ~ 0 >> 1 sigue siendo ~ 0 porque el signo de desplazamiento se extiende.

Consulte aquí: https://stackoverflow.com/a/7632/1974021

Es posible que le interesen los archivos de cabecera constante en limits.hy float.h

Desde limits.h :

 +------------+------------------------------------------------------------------+--------------------------------+ | CHAR_BIT | Number of bits in a char object (byte) | 8 or greater | | SCHAR_MIN | Minimum value for an object of type signed char | -127 (-2^7+1) or less | | SCHAR_MAX | Maximum value for an object of type signed char | 127 (2^7-1) or greater | | UCHAR_MAX | Maximum value for an object of type unsigned char | 255 (2^8-1) or greater | | CHAR_MIN | Minimum value for an object of type char | either SCHAR_MIN or 0 | | CHAR_MAX | Maximum value for an object of type char | either SCHAR_MAX or UCHAR_MAX | | MB_LEN_MAX | Maximum number of bytes in a multibyte character, for any locale | 1 or greater | | SHRT_MIN | Minimum value for an object of type short int | -32767 (-2^15+1) or less | | SHRT_MAX | Maximum value for an object of type short int | 32767 (2^15-1) or greater | | USHRT_MAX | Maximum value for an object of type unsigned short int | 65535 (2^16-1) or greater | | INT_MIN | Minimum value for an object of type int | -32767 (-2^15+1) or less | | INT_MAX | Maximum value for an object of type int | 32767 (2^15-1) or greater | | UINT_MAX | Maximum value for an object of type unsigned int | 65535 (2^16-1) or greater | | LONG_MIN | Minimum value for an object of type long int | -2147483647 (-2^31+1) or less | | LONG_MAX | Maximum value for an object of type long int | 2147483647 (2^31-1) or greater | | ULONG_MAX | Maximum value for an object of type unsigned long int | 4294967295 (2^32-1) or greater | +------------+------------------------------------------------------------------+--------------------------------+ 

Cuando realiza el cambio de bit en i , el comstackdor ve que i es una cantidad con signo y realiza un desplazamiento aritmético hacia la derecha. Parece que quieres que la línea de código realice un cambio lógico hacia la derecha.

Cambia la linea

i >>= 1;

a

i = ((unsigned int)i) >> 1;

Entonces funciona!

 Output: Upper limit: 2147483647 Lower limit: -2147483648