【问题标题】:Convert hex std::string to unsigned char将十六进制 std::string 转换为无符号字符
【发布时间】:2012-11-09 13:39:51
【问题描述】:

我有一个十六进制字符串,想把它转换成一个十六进制无符号字符数组!

std::string hex = "0c45a1bf"

unsigned char hexCh = ""
    [0] = "0c"
    [1] = "45"
    [2] = "a1"
    [3] = "bf"

我希望以 hexCh 显示此行为!

stringstream 和 std::hex 的最佳方式?你有实现吗?!

谢谢

【问题讨论】:

  • 所以你应该遍历你的字符串并逐个字符处理。
  • 澄清问题:您想将每对字符分成一个字符数组还是将每对字符的值存储到unsigned char数组中?

标签: c++ string hex std


【解决方案1】:

假设您想要每对十六进制字符串的

std::string hex = "0c45a1bf";

int main(int argc, char **argv)
{
    union U
    {
        unsigned int value;
        unsigned char components[4];
    };

    U u;

    std::stringstream SS(hex);
    SS >> std::hex >> u.value;

    std::cout << u.components[0] << '\n'; // the 0c value
    std::cout << u.components[1] << '\n'; // the 45 value
    std::cout << u.components[2] << '\n'; // the a1 value
    std::cout << u.components[3] << '\n'; // the bf value
}

您可以将值读入union 并获取每个子部分。

【讨论】:

  • 这是未定义的行为,实际发生的情况取决于系统、架构等。
  • 是的,我知道答案不完整:我假设十六进制字符串将始终适合 unsigned int 并且我没有考虑对齐但是......问题不'不指定平台或将使用什么十六进制格式,我只是认为union 的使用值得知道作为在某些范围内可能的解决方案。
  • 从最后写入的成员以外的成员读取是未定义的行为。更重要的是,在这种情况下,您忽略了字节顺序问题以及int 的大小。使用uint32_t 而不是int 可以轻松解决大小问题。另一方面,字节顺序问题没有简单的解决方案。
  • @JamesKanze 是的,使用像uint32_t 这样的固定大小类型(它在哪里定义?,来自标准?)可以解决部分问题,但是,未定义的十六进制格式的问题并且未定义长度的十六进制字符串仍然存在,处理像aa12345678这样的字符串可能会让人头疼!
  • uint32_t 在 C99 或 C++11 中的 &lt;stdint.h&gt; 中有条件地定义。 (大多数 C++03 编译器也会有它,因为它在 C99 中。)它只在具有 32 位整数类型的机器上定义,所以你不会在一些奇特的机器上找到它。 (Unisys 有,或者至少直到最近才有,有 9 位字节的 36 位架构,和有sizeof(int) == 6 的 48 位架构。但是这样的机器已经变得非常奇特,大多数人不必担心它们。 )
【解决方案2】:

使用std::stringstream + std::hex:

std::stringstream ss;
std::string hex = "0c45a1bf";
std::vector<unsigned char> hexCh;
unsigned int buffer;
int offset = 0;
while (offset < hex.length()) {
   ss.clear();
   ss << std::hex << hex.substr(offset, 2);
   ss >> buffer;
   hexCh.push_back(static_cast<unsigned char>(buffer));
   offset += 2;
}

【讨论】:

    【解决方案3】:

    您可以将整个字符串转换为更大的整数 类型,并从中挑选出字节。类似的东西:

    std::vector<unsigned char>
    asBytes( std::string const& input )
    {
        std::istringstream parser( input );
        uint32_t tmp;
        input >> std::hex >> tmp;
        std::vector<unsigned char> results;
        //  The conversion implicitly does the & 0xFF
        results.push_back( tmp >> 24 );
        results.push_back( tmp >> 16 );
        results.push_back( tmp >>  8 );
        results.push_back( tmp       );
        return results;
    }
    

    或者,您可以创建每个包含两个字符的子字符串,创建 每个都有一个std::istringstream,并从中输入。你 还是要输入大于char的类型,因为&gt;&gt; 一个字符类型只读取 一个 字符,并分配它。 但是你可以把它读成int,然后把int转换成 unsigned char.

    unsigned char
    convertOneByte( std::string::const_iterator begin,
                    std::string::const_iterator end )
    {
        std::istringstream parser( std::string( begin, end ) );
        int tmp;
        parser >> std::hex >> tmp;
        return tmp;
    }
    
    std::vector<unsigned char>
    asBytes( std::string const& input )
    {
        std::vector<unsigned char> results;
        results.push_back( input.begin()    , input.begin() + 2 );
        results.push_back( input.begin() + 2, input.begin() + 4 );
        results.push_back( input.begin() + 4, input.begin() + 6 );
        results.push_back( input.begin() + 6, input.begin() + 8 );
        return results;
    }
    

    (这两个代码都需要更多的错误检查。它们只是 给你一个想法。)

    【讨论】:

      【解决方案4】:

      这两个功能一起完成工作:

      这个很简单:

      inline int char2hex(char c)
      {
         if (c >= '0' && c <= '9') return c - '0';
         if (c >= 'a' && c <= 'f') return c - 'a' + 10;
         if (c >= 'A' && c <= 'F') return c - 'A' + 10;
         throw std::runtime_error("wrong char");
      }
      

      这有点复杂:

      std::vector<unsigned char> str2hex(const std::string& hexStr)
      {
           std::vector<unsigned char> retVal;
           bool highPart = ((hexStr.length() % 2) == 0);  
           // for odd number of characters - we add an extra 0 for the first one:
           if (!highPart)
               retVal.push_back(0);
           std::for_each(hexStr.begin(), hexStr.end(), 
              [&](char nextChar) {
                 if (highPart) 
                     // this is first char for the given hex number:
                     retVal.push_back(0x10 * char2hex(nextChar));
                 else
                    // this is the second char for the given hex number
                    retVal.back() += char2hex(nextChar);
                 highPart = !highPart;
             }
           );
      
          return retVal;
      }
      

      还有 example 它的工作原理:

      int main() {
        std::string someHex =  "c45a1bf";
        std::vector<unsigned char> someUHex = str2hex(someHex);
        std::copy(someUHex.begin(), someUHex.end(), std::ostream_iterator<int>(std::cout << std::hex, ""));
      }
      

      【讨论】:

        【解决方案5】:

        一个可能的解决方案:(感谢 Denis Ermolin):

        void ClassA::FuncA(unsigned char *answer)
        {
            std::string hex = "0c45a1bf";
            std::stringstream convertStream;
        
            // if you have something like "0c 45 a1 bf" -> delete blanks
            hex.erase( std::remove(hex.begin(), hex.end(), ' '), hex.end() );
        
            int offset = 0, i = 0;      
            while (offset < hex.length()) 
            {
                unsigned int buffer;
        
                convertStream << std::hex << hex.substr(offset, 2);         
                convertStream >> std::hex >> buffer;
        
                answer[i] = static_cast<unsigned char>(buffer);
        
                offset += 2;
                i++;
        
                // empty the stringstream
                convertStream.str(std::string());
                convertStream.clear();
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2012-03-25
          • 2015-01-11
          • 1970-01-01
          • 2017-01-11
          • 2013-03-22
          • 1970-01-01
          • 1970-01-01
          • 2011-08-24
          • 2018-01-31
          相关资源
          最近更新 更多