c - tipos - unsigned int para que sirve
unsigned long int acepta valores fuera de rango (1)
Esta es mi segunda pregunta para este código. este código proviene de un guión modificado en la página 66 de la "Séptima programación de Sams Teach Yourself C". Después de copiar el guión del libro, lo modifiqué (solo un poco) para hacerlo más interesante.
- Agregué algunas constantes y variables adicionales para permitirle aceptar un mayor valor de entrada / salida.
- porque la entrada / salida es del tipo "unsigned long int", que tiene un rango de 0 - 2147483647, configuré que era el LIMIT.
- Luego agregué un "else" al final del programa para tratar todas las entradas por encima de ese valor. Solo quería hacer un experimento para ver si se registraba, valores que excedían el rango.
- la primera vez que publiqué una pregunta sobre un error matemático en el código que no pude encontrar por mi cuenta. Eso fue resuelto
Aquí hay algunos ejemplos de resultados:
[bad_cat@KittyLitter LearningCode]$ gcc SamsC.04.seconds.c
[bad_cat@KittyLitter LearningCode]$ ./a.out
Enter the number of seconds ( > 0, < 2147483647 ):
2147483646
2147483646 seconds is equal to 68 y 35 d, 3 h, 14 m, and 6 s
[bad_cat@KittyLitter LearningCode]$ ./a.out
Enter the number of seconds ( > 0, < 2147483647 ):
2147483647
2147483647 seconds is equal to [bad_cat@KittyLitter LearningCode]$ ./a.out
Enter the number of seconds ( > 0, < 2147483647 ):
2147483650
-2147483646 seconds is equal to error: -2147483646 is an excessive amount of seconds.
range for seconds must be between 0 and 2147483647!
If number of seconds exceeds 2147483647, then it is beyond range for type ''int''.
EXITING seconds program.
[bad_cat@KittyLitter LearningCode]$ ./a.out
Enter the number of seconds ( > 0, < 2147483647 ):
9876543210
1286608618 seconds is equal to 40 y 291 d, 7 h, 16 m, and 58 s
[bad_cat@KittyLitter LearningCode]$
Aquí está el código:
/* Illustrates the modulus operator. */
/* inputs a number of seconds, and converts to hours, minutes, and seconds. */
// minute = 60 seconds : 60
// hour = 60 * 60 seconds : 3600
// day = 24 * 60 * 60 seconds : 86400
// year = 365 * 24 * 60 * 60 seconds : 31536000
#include <stdio.h> // from original script
/* Define constants */
#define SECS_PER_MIN 60 // from original script
#define MIN_PER_HOUR 60
#define HOURS_PER_DAY 24
#define DAYS_PER_YEAR 365
#define SECS_PER_YEAR 31536000
#define SECS_PER_HOUR 3600 // from original script
#define SECS_PER_DAY 86400
#define LIMIT 2147483647
unsigned seconds, minutes, hours, days, years, secs_remain, mins_remain, hours_remain, days_remain; // modified from original script
int main(void) // from original script
{
seconds = minutes = hours = days = years = secs_remain = mins_remain = hours_remain = days_remain = 0;
/* Input the number of seconds. */
printf( "Enter the number of seconds ( > 0, < %d ): /n", LIMIT ); // modified from original script
scanf( "%d", &seconds ); // from original script
years = seconds /SECS_PER_YEAR;
days = seconds / SECS_PER_DAY;
hours = seconds / SECS_PER_HOUR; // from original script
minutes = seconds / SECS_PER_MIN; // from original script
days_remain = days % DAYS_PER_YEAR;
hours_remain = hours % HOURS_PER_DAY;
mins_remain = minutes % MIN_PER_HOUR; // modified from original script
secs_remain = seconds % SECS_PER_MIN; // from original script
printf( "%d seconds is equal to ", seconds ); // from original script
if ( seconds < SECS_PER_HOUR )
{
printf( "%d m, and %d s/n", minutes, secs_remain );
return 0;
}
else if((seconds >= SECS_PER_HOUR ) && (seconds < SECS_PER_DAY ))
{
printf( "%d h, %d m, and %d s/n", hours, mins_remain, secs_remain ); // from original script
return 0; // from original script
}
else if((seconds >= SECS_PER_DAY ) && (seconds < SECS_PER_YEAR ))
{
printf( "%d d, %d h, %d m, and %d s/n", days, hours_remain, mins_remain, secs_remain );
return 0;
}
else if((seconds >= SECS_PER_YEAR ) && (seconds < LIMIT ))
{
printf( "%d y %d d, %d h, %d m, and %d s/n", years, days_remain, hours_remain, mins_remain, secs_remain );
return 0;
}
else if(seconds > LIMIT )
{
printf("error: %d is an excessive amount of seconds./n", seconds);
printf("range for seconds must be between 0 and %d!/n", LIMIT );
printf("If number of seconds exceeds %d, then it is beyond range for type ''int''./n", LIMIT );
printf("EXITING seconds program. /n");
return 1;
}
}
Gracias, cambié todo "%d"
a "%u"
y Límite. También lo he reunido para futuras referencias:
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("/n");
printf("The number of bits in a byte =/t/t/t/t %d/n", CHAR_BIT);
printf("The maximum number of bytes in a multi-byte character =/t %d/n", MB_LEN_MAX);
printf("The minimum value of SIGNED CHAR =/t/t/t %d/n", SCHAR_MIN);
printf("The maximum value of SIGNED CHAR =/t/t/t %d/n", SCHAR_MAX);
printf("The maximum value of UNSIGNED CHAR =/t/t/t %d/n", UCHAR_MAX);
printf("The minimum value of SHORT INT =/t/t/t %d/n", SHRT_MIN);
printf("The maximum value of SHORT INT =/t/t/t %d/n", SHRT_MAX);
printf("The maximum value for an UNSIGNED SHORT INT =/t/t %u/n", USHRT_MAX);
printf("The minimum value of INT =/t/t/t/t %d/n", INT_MIN);
printf("The maximum value of INT =/t/t/t/t %d/n", INT_MAX);
printf("The maximum value for an UNSIGNED INT =/t/t/t %u/n", UINT_MAX);
printf("The minimum value of CHAR =/t/t/t/t %d/n", CHAR_MIN);
printf("The maximum value of CHAR =/t/t/t/t %d/n", CHAR_MAX);
printf("The minimum value of LONG =/t/t/t/t %ld/n", LONG_MIN);
printf("The maximum value of LONG =/t/t/t/t %ld/n", LONG_MAX);
printf("The maximum value for an UNSIGNED LONG INT =/t/t %Lu/n", ULONG_MAX);
printf("/n");
return(0);
}
Parece que intentas asegurarte de que el usuario no escriba un valor demasiado grande para que se mantenga la variable de seconds
. Entonces lees un valor en seconds
y luego (entre otras cosas) intentas verificar si es demasiado grande. Pero el problema es que, en el momento en que ha leído un valor demasiado grande en seconds
, no puede decir realmente qué es, porque el valor es demasiado grande para que los contengan los seconds
, por lo que se ha transformado en algún otro valor.
Ahora, es un poco más complicado que eso, porque has declarado los seconds
como unsigned int
. Es probable que el rango real de seconds
en su sistema sea de 0 a 4294967295. Por lo tanto, cuando ingresa un valor como 2147483648, los seconds
pueden contener este valor, aunque es mayor que LIMIT
, por lo que puede pasar al else
cláusula.
Pero luego, cuando llegas a la cláusula else
, imprimes el valor de seconds
usando %d
. Pero %d
es para entradas firmadas, no sin firmar. Entonces es por eso que estás viendo esos valores negativos extraños.
No estoy seguro de que esto responda a su pregunta, y no estoy seguro de qué es lo que realmente quiere que haga su código (es decir, si prefiere usar aritmética con o sin firma), así que no proporciono ninguna código "fijo" para que intentes. Pero espero que esto ayude a explicar lo que está pasando. Si tienes mas preguntas, solo pregunta.
Adición: lo que está sucediendo aquí es que cuando se desbordan, los enteros sin signo "envuelven" desde el valor demasiado alto de nuevo a 0. Además, aunque no está garantizado, los enteros con signo tienden a envolverse también, desde su propio demasiado alto valor de nuevo al valor grande, negativo, demasiado bajo.
Para enteros de 32 bits, los valores se ajustan en un ciclo de 4294967296. Por lo tanto, sin signo puede ir de 0 a 4294967295, y si intentas atascar en 4294967296 obtienes 0, y si pruebas 4294967297 obtienes 1, y si lo intentas 4294967298 obtienes 2, etc.
Cuando están firmados, los valores legales van desde -2147483648 a +2147483647, y si intentas atascar en +2147483648 obtienes -2147483648, y si tratas de atascar en +2147483649 obtienes -2147483647, etc.
Entonces, dado que 2147483650 es mayor que 2147483647, no cabrá, y el valor que obtienes es 2147483650 - 4294967296 = -2147483646. ¿Qué hay de 9876543210? Demasiado grande, y 9876543210 - 4294967296 = 5581575914 que todavía es demasiado grande, pero 5581575914 - 4294967296 = 1286608618 que no encaja. Entonces es por eso que obtuviste ese extraño número 1286608618 en tu último ejemplo.