【问题标题】:C++ convert hex string to signed integerC ++将十六进制字符串转换为有符号整数
【发布时间】:2021-11-05 09:20:29
【问题描述】:

我想在 C++ 中将十六进制字符串转换为 32 位有符号整数。

因此,例如,我有十六进制字符串“ffffeffe”。它的二进制表示是 11111111111111101111111111111110。它的有符号整数表示是:-65538。

如何在 C++ 中进行这种转换?这也需要对非负数起作用。例如十六进制字符串“0000000A”,二进制为00000000000000000000000000001010,十进制为10。

【问题讨论】:

标签: c++ integer hex signed


【解决方案1】:

对于那些希望将数字基数转换为无符号数的人来说,在 C/C++ 中以最小的依赖性自己做是非常简单的(语言本身不提供的唯一运算符是 pow() 函数)。

在数学术语中,以 b 为基数且具有 n 位数的正序数 d 可以使用以下方法转换为以 10 为基数:

示例:转换基数为 16 的数字 00f 如下所示:

= 0*16^2 + 0*16^1 + 16*16^0 = 15

C/C++ 示例:

#include <math.h>

unsigned int to_base10(char *d_str, int len, int base)
{
    if (len < 1) {
        return 0;
    }
    char d = d_str[0];
    // chars 0-9 = 48-57, chars a-f = 97-102
    int val = (d > 57) ? d - ('a' - 10) : d - '0';
    int result = val * pow(base, (len - 1));
    d_str++; // increment pointer
    return result + to_base10(d_str, len - 1, base);
}

int main(int argc, char const *argv[])
{
    char n[] = "00f"; // base 16 number of len = 3
    printf("%d\n", to_base10(n, 3, 16));
}

【讨论】:

    【解决方案2】:

    只需使用 stoi/stol/stoll 例如:

    std::cout << std::stol("fffefffe", nullptr, 16) << std::endl;
    

    输出:4294901758

    【讨论】:

      【解决方案3】:

      试试这个。这个解决方案有点冒险。没有支票。字符串只能具有十六进制值,并且字符串长度必须与返回类型大小匹配。但不需要额外的标题。

      char hextob(char ch)
      {
          if (ch >= '0' && ch <= '9') return ch - '0';
          if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
          if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
          return 0;
      }
      template<typename T>
      T hextot(char* hex)
      {
          T value = 0;
          for (size_t i = 0; i < sizeof(T)*2; ++i)
              value |= hextob(hex[i]) << (8*sizeof(T)-4*(i+1));
          return value;
      };
      

      用法:

      int main()
      {
          char str[4] = {'f','f','f','f'};
          std::cout << hextot<int16_t>(str)  << "\n";
      }
      

      注意:字符串的长度必须能被2整除

      【讨论】:

        【解决方案4】:

        使用std::stringstream

        unsigned int x;   
        std::stringstream ss;
        ss << std::hex << "fffefffe";
        ss >> x;
        

        以下示例生成 -65538 作为其结果:

        #include <sstream>
        #include <iostream>
        
        int main() {
            unsigned int x;   
            std::stringstream ss;
            ss << std::hex << "fffefffe";
            ss >> x;
            // output it as a signed type
            std::cout << static_cast<int>(x) << std::endl;
        }
        

        在新的 C++11 标准中,有一些新的实用函数可供您使用!具体来说,有一系列“字符串到数字”函数(http://en.cppreference.com/w/cpp/string/basic_string/stolhttp://en.cppreference.com/w/cpp/string/basic_string/stoul)。这些本质上是围绕 C 的字符串到数字转换函数的薄包装,但知道如何处理 std::string

        因此,较新代码的最简单答案可能如下所示:

        std::string s = "0xfffefffe";
        unsigned int x = std::stoul(s, nullptr, 16);
        

        注意:以下是我的原始答案,正如编辑所说,这不是一个完整的答案。对于功能性解决方案,请将代码粘贴在行上方:-)。

        似乎因为lexical_cast&lt;&gt; 被定义为具有流转换语义。可悲的是,流不理解“0x”表示法。所以boost::lexical_cast 和我的手卷都不能很好地处理十六进制字符串。上述手动将输入流设置为十六进制的解决方案可以很好地处理它。

        Boost has some stuff 也可以这样做,它也有一些很好的错误检查功能。你可以这样使用它:

        try {
            unsigned int x = lexical_cast<int>("0x0badc0de");
        } catch(bad_lexical_cast &) {
            // whatever you want to do...
        }
        

        如果您不想使用 boost,这里有一个不进行错误检查的轻量级词法转换:

        template<typename T2, typename T1>
        inline T2 lexical_cast(const T1 &in) {
            T2 out;
            std::stringstream ss;
            ss << in;
            ss >> out;
            return out;
        }
        

        你可以这样使用:

        // though this needs the 0x prefix so it knows it is hex
        unsigned int x = lexical_cast<unsigned int>("0xdeadbeef"); 
        

        【讨论】:

        • 当我使用该方法时,我最终得到一个整数值 152144602
        • @SteveWilkinson:阅读以“EDIT”开头的段落。它解释了您需要如何使用std::hex
        • 对于stringstreams 应检查ss.good() &amp;&amp; ss.eof() 以确保没有发生错误。
        • 这个“stoul”保存了我的逻辑
        【解决方案5】:

        我今天遇到了同样的问题,这是我解决它的方法,所以我可以保留 lexical_cast

        typedef unsigned int    uint32;
        typedef signed int      int32;
        
        class uint32_from_hex   // For use with boost::lexical_cast
        {
            uint32 value;
        public:
            operator uint32() const { return value; }
            friend std::istream& operator>>( std::istream& in, uint32_from_hex& outValue )
            {
                in >> std::hex >> outValue.value;
            }
        };
        
        class int32_from_hex   // For use with boost::lexical_cast
        {
            uint32 value;
        public:
            operator int32() const { return static_cast<int32>( value ); }
            friend std::istream& operator>>( std::istream& in, int32_from_hex& outValue )
            {
                in >> std::hex >> outvalue.value;
            }
        };
        
        uint32 material0 = lexical_cast<uint32_from_hex>( "0x4ad" );
        uint32 material1 = lexical_cast<uint32_from_hex>( "4ad" );
        uint32 material2 = lexical_cast<uint32>( "1197" );
        
        int32 materialX = lexical_cast<int32_from_hex>( "0xfffefffe" );
        int32 materialY = lexical_cast<int32_from_hex>( "fffefffe" );
        // etc...
        

        (当我在寻找一种不那么糟糕的方式时发现了这个页面:-)

        干杯, A.

        【讨论】:

        • 代码有轻微的编译错误 - outvalue 没有定义(应该是 outValue)。
        【解决方案6】:

        对于同时适用于 C 和 C++ 的方法,您可能需要考虑使用标准库函数 strtol()。

        #include <cstdlib>
        #include <iostream>
        using namespace std;
        
        int main() {
            string s = "abcd";
            char * p;
            long n = strtol( s.c_str(), & p, 16 );
            if ( * p != 0 ) { //my bad edit was here
                cout << "not a number" << endl;
            }
            else {
                cout << n << endl;
            }
        }
        

        【讨论】:

        • 您应该使用strtoul 而不是strtol。使用strtol时会有+ overflow。使用strtoul 不会溢出,返回值将转换为long 以产生正确的结果(-65538)。所以你的答案几乎是正确的:)
        • +1。因为 strtol(或 strtoul)比使用 stringstream 更快。
        【解决方案7】:

        这是我在其他地方找到的一种简单有效的方法:

        string hexString = "7FF";
        int hexNumber;
        sscanf(hexString.c_str(), "%x", &hexNumber);
        

        请注意,您可能更喜欢使用无符号长整数/长整数来接收值。 另一个注意事项, c_str() 函数只是将 std::string 转换为 const char* 。

        因此,如果您已准备好 const char*,请继续直接使用该变量名称,如下所示[我还展示了 unsigned long 变量用于更大的十六进制数的用法。不要将它与使用 const char* 而不是 string] 的情况混淆:

        const char *hexString = "7FFEA5"; //Just to show the conversion of a bigger hex number
        unsigned long hexNumber; //In case your hex number is going to be sufficiently big.
        sscanf(hexString, "%x", &hexNumber);
        

        这工作得非常好(只要您根据需要使用适当的数据类型)。

        【讨论】:

          【解决方案8】:

          这对我有用:

          string string_test = "80123456";
          unsigned long x;
          signed long val;
          
          std::stringstream ss;
          ss << std::hex << string_test;
          ss >> x;
          // ss >> val;  // if I try this val = 0
          val = (signed long)x;  // However, if I cast the unsigned result I get val = 0x80123456 
          

          【讨论】:

            【解决方案9】:

            Andy Buchanan,就坚持使用 C++ 而言,我喜欢你的,但我有一些 mod:

            template <typename ElemT>
            struct HexTo {
                ElemT value;
                operator ElemT() const {return value;}
                friend std::istream& operator>>(std::istream& in, HexTo& out) {
                    in >> std::hex >> out.value;
                    return in;
                }
            };
            

            类似

            uint32_t value = boost::lexical_cast<HexTo<uint32_t> >("0x2a");
            

            这样你就不需要每个 int 类型一个 impl。

            【讨论】:

            • 我也会采取这一步,但我发现我喜欢限制尖括号的扩散。对于这种情况,我觉得打破“不要重复代码”规则是合理的。 :-)
            • 不幸的是,这是必要的,但做得很好。添加到我的个人 STL/Boost 扩展/修复标题中。谢谢!
            • 不幸的是,这只适用于无符号转换。所以你不能将 0xFFFFFFFF 转换为 -1。
            • @fmuecke:那是因为 0xFFFFFFFF 是有符号整数溢出,这是未定义的行为。
            【解决方案10】:

            strtoul 的工作示例将是:

            #include <cstdlib>
            #include <iostream>
            using namespace std;
            
            int main() { 
                string s = "fffefffe";
                char * p;
                long n = strtoul( s.c_str(), & p, 16 ); 
                if ( * p != 0 ) {  
                    cout << "not a number" << endl;
                }    else {  
                    cout << n << endl;
                }
            }
            

            strtolstring 转换为 long。在我的电脑上numeric_limits&lt;long&gt;::max() 给出0x7fffffff。显然0xfffefffe 大于0x7fffffff。所以strtol 返回MAX_LONG 而不是想要的值。 strtoulstring 转换为 unsigned long 这就是在这种情况下没有溢出的原因。

            好的,strtol 在转换前考虑输入字符串不是 32 位有符号整数。 strtol的搞笑样例:

            #include <cstdlib>
            #include <iostream>
            using namespace std;
            
            int main() { 
                string s = "-0x10002";
                char * p;
                long n = strtol( s.c_str(), & p, 16 ); 
                if ( * p != 0 ) {  
                    cout << "not a number" << endl;
                }    else {  
                    cout << n << endl;
                }
            }
            

            上面的代码在控制台中打印-65538

            【讨论】:

              猜你喜欢
              • 2019-05-03
              • 2017-08-12
              • 2012-08-29
              • 2011-04-11
              • 2018-01-31
              • 2015-11-29
              相关资源
              最近更新 更多