unsigned long int接受超出范围的值

时间:2017-02-11 13:18:59

标签: c variables int range

这是我对此代码的第二个问题。 此代码来自“Sams教你自己C编程”第7版第66页的修改过的脚本。 将脚本复制出书后,我对其进行了修改(只是一点点),使其更有趣。

  • 我添加了一些额外的常量和变量,以使其能够接受更大的输入/输出值。
  • 因为输入/输出是“unsigned long int”类型,其范围为0 - 2147483647,我将其设置为LIMIT。
  • 然后我在程序的最后添加了一个“else”来处理超过该值的所有输入。我只是想做一个实验,看它是否会注册,超出范围的值。
  • 我第一次在我自己找不到的代码中发布了一个关于数学错误的问题。那已经解决了。

以下是一些示例输出:

[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]$ 

以下是代码:

/* 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;
         }
    }

谢谢,我已将所有"%d"更改为"%u"和限制。 我也将它们放在一起以供将来参考:

#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);
}

1 个答案:

答案 0 :(得分:3)

您似乎正在努力确保用户输入的seconds变量的值不会过大。因此,您将值读入seconds,然后(除其他外),您尝试检查它是否太大。但问题是,当你在seconds中读取太大的值时,你无法真正说出它是什么,因为seconds的值太大了坚持,所以它已被转化为其他价值!

现在,它有点复杂,因为您已将seconds声明为unsigned int。您系统上seconds的实际范围可能是0到4294967295.因此,当您输入类似2147483648的值时,seconds 可以保留此值值 - 尽管它大于LIMIT,所以你确实通过了else子句。

但是,当您进入else子句时,使用seconds打印出%d的值。但是%d用于签名的整数,而不是未签名的。这就是为什么你会看到那些奇怪的负面价值。

我不确定这是否能回答您的问题,而且我不确定您真正想要您的代码做什么(也就是说,您是否真的宁愿使用有符号或无符号算术),所以我没有提供任何&#34;固定&#34;代码供您试用。但我希望这有助于解释发生了什么。如果您有更多问题,请询问。

附录:这里实际发生的是当它们溢出时,无符号整数和#34;环绕&#34;从太高的值回到0.此外,尽管它没有得到保证,但有符号的整数也往往会从它们自己太高的价值回归到大的,负的,太低的价值。

对于32位整数,值循环在4294967296的循环中。所以unsigned可以从0到4294967295,如果你试图在4294967296中堵塞,你得到0,如果你尝试4294967297,你得到1,如果你尝试4294967298,你得到2,等等。

当他们签约时,合法值从-2147483648变为+2147483647,如果你试图堵塞+2147483648,你得到-2147483648,如果你试图堵塞+2147483649,你得到-2147483647等

因此,由于2147483650大于2147483647,因此它不合适,您获得的值是2147483650 - 4294967296 = -2147483646。怎么样9876543210?方式太大了,9876543210 - 4294967296 = 5581575914这仍然太大,但5581575914 - 4294967296 = 1286608618哪个合适。这就是为什么你在上一个例子中得到了那个奇怪的数字1286608618的原因。