【问题标题】:Htoi incorrect output at 10 digitsHtoi 在 10 位时输出不正确
【发布时间】:2016-02-16 02:22:10
【问题描述】:

当我输入 0x123456789 我得到不正确的输出,我不知道为什么。起初我认为这是一个最大可能的 int 值问题,但我将变量更改为 unsigned long 并且问题仍然存在。

#include <iostream>
using namespace std;

long htoi(char s[]);

int main()
{
    cout << "Enter Hex \n";
    char hexstring[20];
    cin >> hexstring;
    cout << htoi(hexstring) << "\n";

}

//Converts string to hex
long htoi(char s[])
{
    int charsize = 0;
    while (s[charsize] != '\0')
    {
        charsize++;
    }
    int base = 1;
    unsigned long total = 0;
    unsigned long multiplier = 1;
    for (int i = charsize; i >= 0; i--)
    {
        if (s[i] == '0' || s[i] == 'x' || s[i] == 'X' || s[i] == '\0')
        {
            continue;
        }
        if ( (s[i] >= '0') && (s[i] <= '9') )
        {
            total = total + ((s[i] - '0') * multiplier);
            multiplier = multiplier * 16UL;
            continue;
        }
        if ((s[i] >= 'A') && (s[i] <= 'F'))
        {
            total = total + ((s[i] - '7') * multiplier); //'7' equals 55 in decimal, while 'A' equals 65
            multiplier = multiplier * 16UL;
            continue;
        }
        if ((s[i] >= 'a') && (s[i] <= 'f'))
        {
            total = total + ((s[i] - 'W') * multiplier); //W equals 87 in decimal, while 'a' equals 97
            multiplier = multiplier * 16UL;
            continue;
        }
    }
    return total;
}

【问题讨论】:

  • 使用调试器或打印语句逐步执行代码。你知道你对每一行的期望。对照实际值检查它。
  • 如果我可以提出一个建议,但是,你是在倒退。从 第一个 数字开始,将其与您的结果 (total) 相结合,然后乘以 16。重复直到没有数字为止。顺便说一句,如果您使用签名号码,您会遇到问题。使用_unsigned_ long long
  • @Duthomhas 如果向后完成会更容易,因为十六进制是从右到左读取的。如果我从左到右阅读,我需要将我的代码重新编写到乘数以最高幂(由十六进制数字的数量驱动)开始的位置,并在每次读取十六进制字符时除以 16。此外,当用户以以下形式输入十六进制时,乘数会不必要地被除:0xABCDEFG 因为 0 是一个十六进制字符,如果 0x 是按顺序排列的,这会使我的代码复杂化以忽略前两个字符。向后阅读将是编写此代码的最简单和最有效的方法(请参阅 sol)。
  • 您不得不问我们如何实现它,但不知何故您知道如何做?这很有趣,因为我可以用三行代码完成。提示:当你在学习的时候,不要假设你比别人更了解事物。顺便说一句,就像 any 数字一样,十六进制是从左到右读取的;最重要到最不重要。
  • @Duthomhas 如果我让您觉得自己名誉扫地,我深表歉意,那不是我的本意。我知道我是一个初学者,所以我不相信我比其他人更了解代码。我认为看到您的示例在三行中将十六进制转换为 int 而不使用 C/C++ 库中预先编写的解析器因此 strtol 函数会很有趣。我总是乐于扩展我的知识。我找不到任何地方严格从左到右读取十六进制,因为我已经看到它是双向的,但我确实喜欢从最重要到最不重要的想法。

标签: c++ string function hex decimal


【解决方案1】:

long 在您的计算机上可能也是 32 位的。试试long long

【讨论】:

    【解决方案2】:

    您需要超过 32 位来存储该数字。您的 long 类型可能只有 32 位。

    使用 std::uint64_t 代替。这始终是 64 位无符号类型。如果您的编译器不支持,请使用 long long。那必须至少是 64 位。

    【讨论】:

      【解决方案3】:

      这个想法遵循数字的多项式性质。 123是一样的

      1*102 + 2*101 + 3*100

      换句话说,我必须将第一个数字乘以十两次。我必须将 2 乘以 1一次。我将最后一位数字乘以一。同样,从左到右阅读:

      • 将 0 乘以 10 并加上 1 → 0*10+1 = 1。
      • 将其乘以 10 并加上 2 → 1*10+2 = 12。
      • 将其乘以 10 并加上 3 → 12*10+3 = 123。

      我们会做同样的事情:

      #include <cctype>
      #include <ciso646>
      #include <iostream>
      using namespace std;
      
      unsigned long long hextodec( const std::string& s )
      {
        unsigned long long result = 0;
        for (char c : s)
        {
          result *= 16;
          if (isdigit( c )) result |= c - '0';
          else              result |= toupper( c ) - 'A' + 10;
        }
        return result;
      }
      
      int main( int argc, char** argv )
      {
        cout << hextodec( argv[1] ) << "\n";
      }
      

      您可能会注意到该函数不止三行。为了清楚起见,我这样做了。 C++ 习惯用法可以使循环变成一行:

      for (char c : s)
        result = (result << 4) | (isdigit( c ) ? (c - '0') : (toupper( c ) - 'A' + 10));
      

      您也可以根据需要进行验证。我提出的并不是进行数字到值转换的唯一方法。还有其他同样好的方法(有些更好)。

      我希望这会有所帮助。

      【讨论】:

      • 您几乎完全使用惯用语来缩短代码实际上非常了不起。如果你想忽略传递给函数的字符串的“0x”部分,你会怎么写?
      • if (s.size()&gt;2 and s[0]=='0' and std::toupper(s[1])=='X') return hextodec(s.substr(2));
      • if (toupper(s).find("0X") == 0) return hextodec(s.substr(2));(其中 toupper() 是一个接受字符串的自定义函数)。方法有很多。
      【解决方案4】:

      我发现发生了什么,当我输入“1234567890”时,它会跳过“0”,所以我不得不修改代码。另一个问题是 long 确实是 32 位,所以我按照@Bathsheba 的建议将其更改为 uint64_t 。这是最终的工作代码。

      #include <iostream>
      using namespace std;
      
      uint64_t htoi(char s[]);
      
      int main()
      {
          char hexstring[20];
          cin >> hexstring;
          cout << htoi(hexstring) << "\n";
      
      }
      
      //Converts string to hex
      uint64_t htoi(char s[])
      {
          int charsize = 0;
          while (s[charsize] != '\0')
          {
              charsize++;
          }
          int base = 1;
          uint64_t total = 0;
          uint64_t multiplier = 1;
          for (int i = charsize; i >= 0; i--)
          {
              if (s[i] == 'x' || s[i] == 'X' || s[i] == '\0')
              {
                  continue;
              }
              if ( (s[i] >= '0') && (s[i] <= '9') )
              {
                  total = total + ((uint64_t)(s[i] - '0') * multiplier);
                  multiplier = multiplier * 16;
                  continue;
              }
              if ((s[i] >= 'A') && (s[i] <= 'F'))
              {
                  total = total + ((uint64_t)(s[i] - '7') * multiplier); //'7' equals 55 in decimal, while 'A' equals 65
                  multiplier = multiplier * 16;
                  continue;
              }
              if ((s[i] >= 'a') && (s[i] <= 'f'))
              {
                  total = total + ((uint64_t)(s[i] - 'W') * multiplier); //W equals 87 in decimal, while 'a' equals 97
                  multiplier = multiplier * 16;
                  continue;
              }
          }
          return total;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 2021-03-05
        • 2015-01-08
        • 1970-01-01
        相关资源
        最近更新 更多