【问题标题】:Unsigned long long overflow无符号长长溢出
【发布时间】:2016-05-22 15:12:57
【问题描述】:

我试图理解为什么这个程序在 2^20-1 值之后会溢出。我所有的变量都声明为 unsigned long long,但是当我输入 1048756 2^20 时,它进入了溢出,而不是将其转换为二进制数。我以为u-l-l的范围是2^64-1。 我包含了limits.h库,最大值是8个字节。这是代码:

#include <stdio.h>
int main(){
  unsigned long long n = 100000000;
  printf("%llu \n",decimal_binary(n));
  return 0;
}

unsigned long long decimal_binary(unsigned long long n)  
{
  unsigned long long rem, i=1, binary=0;
  while (n!=0)
  {
    rem=n%2; 
    n/=2;
    binary+=rem*i;
    i*=10;
  }
  return binary;
}

输出是: 14184298036271661312(显然不是二进制数)

【问题讨论】:

  • @callyalater - 无论系统如何,unsigned long long 至少具有问题中指示的范围,即从 0 到 2^64 - 1。
  • 请缩进您的代码。
  • unsigned long long decimal_binary(unsigned long long n) 未在使用前声明。确保在您的编译器中启用警告。
  • 使用 OP 的方法,代码需要大约 89 位整数才能正确显示 decimal_binary(100000000) 的结果。
  • 1048756₁₀ 是 100000000000000000000₂ (2²⁰)。您的 decimal_binary 函数正在尝试将其转换为 100000000000000000000₁₀ (10²⁰)。这需要一个至少 67 位宽的无符号整数。适合 64 位无符号整数的最大值约为 1.8447x10¹⁹。你看到问题了吗?

标签: c++ c printf scanf


【解决方案1】:
 18446744073709551615 // 2^64-1 
100000000000000000000 // 2^20 in your funny "decimal binary"

现在看到问题了吗?

顺便说一句,如果你想摆脱平台依赖性,请使用stdint.h 中的uint64_t 而不是unsigned long long

【讨论】:

  • 注意:兼容的 C 编译器/平台不需要提供uint64_t
  • 为了澄清之前的评论,@chux 是迂腐的。所有编译器 OP 都可能遇到 do 支持 uint64_t。您绝对不应该将该评论作为不使用这些类型的理由。
  • unsigned long long 保证存在(假设 C99 或更高版本),并且保证具有至少 0 到 2**64-1 的范围。如果您不需要uint64_t 提供的额外保证(无填充位,正好 64 位),使用unsigned long long 没有任何问题。
  • uint64_t 引入了强大的平台依赖性。除非目标平台具有原生 64 位 hardware 类型,否则不允许这样做。 unsigned long long 始终至少为 64 位,uint_fast64_tuint_least64_t 也是如此,并且所有这三个都存在于所有平台的一致编译器上。
  • @PeteBecker 你有关于uint64_t 需要hardware 支持声明的参考吗?一个快速的谷歌并没有带来任何东西,这对我来说听起来很牵强。毕竟,我们已经在 16 位架构上使用了 long
【解决方案2】:

看起来你真正想要的是以二进制格式输出一个数字。您不能将转换重新转换为这样的整数类型。你需要构造一个字符串:

void decimal_binary(unsigned long long n, char str[])
{
  unsigned long long rem, len=0, temp, i;
  while (n!=0)
  {
    rem=n%2;
    n/=2;
    // put the binary digit into the string
    str[len++] = rem ? '1' : '0';
  }
  str[len] = '\x0';
  // the digits were inserted in reverse order, so reverse the string.
  for (i=0;i<=len/2;i++) {
    temp = str[i];
    str[i] = str[len-1-i];
    str[len-1-i] = temp;
  }
}

int main(void){
    char buff[200];
    unsigned long long n = 100000000;
    decimal_binary(n,buff);
    printf("%s \n",buff);
    return 0;
}

输出:

101111101011110000100000000

【讨论】:

    【解决方案3】:

    让您的代码检测数学何时变得太大。

    #include <stdio.h>
    #include <limits.h>
    
    unsigned long long decimal_binary(unsigned long long n)
    {
      unsigned long long rem, i=1, binary=0, n0;
      n0 = n;
      while (n!=0)
      {
        rem=n%2;
        n/=2;
        binary+=rem*i;
        if (i > ULLONG_MAX/10) {
          printf("OF %llu %llu\n", n0 , i);
          return 0;
        }
        i*=10;
      }
      return binary;
    }
    
    
    int main(){
      unsigned long long n = 100000000;
      printf("%llu %llu\n",n,decimal_binary(n));
      n = 100000;
      printf("%llu %llu\n",n, decimal_binary(n));
      return 0;
    }
    

    输出

    OF 100000000 10000000000000000000
    100000000 0 
    100000 11000011010100000 
    

    【讨论】:

      【解决方案4】:
      main()
      {
      unsigned long long n = 100000000;
      int i;
      for(i=sizeof(unsigned long long int)*8-1;i>=0;printf("%llu",n>>i--&1));`
      }
      OUTPUT::00000000 00000000 00000000 00000000 00000101 11110101 11100001 00000000
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-10
        • 1970-01-01
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多