【问题标题】:Converting a sequence of bytes to ASCII representation and vice-versa将字节序列转换为 ASCII 表示,反之亦然
【发布时间】:2011-08-30 13:15:19
【问题描述】:

假设我们有一个 uint8_t 向量:{ 0x12 0x34 0xab 0xcd }。我发现我可以使用 ostringstream 将其转换为字符串 "1234abcd"(没有空格,没有 0x 前缀)。但我不能简单地用 istringstream 将它转换回来,显然因为它没有空格。 hex + setw(2) 机械手没有帮助。是否有任何简单的方法可以将这些字符串转换为相应的字节序列(至少除了编写我自己的解析器)?不能在 ASCII 字符串中引入空格和其他分隔符。

【问题讨论】:

    标签: c++ string stl


    【解决方案1】:

    您可以创建一个代理对象,从您的istringstream 中精确读取两个字符

    struct U8 {
      unsigned int datum;
      friend std::istream& operator>>(std::istream&is, U8& u) {
        char s[3] = "xx";
        if(!((is>>s[0]) && (is>>s[1]) && (std::istringstream(s) >> std::hex >> u.datum)))
          is.setstate(std::ios::badbit);
        return is;
      }
      operator unsigned int() const { return datum; }
    };
    

    你会这样使用它:

    U8 nextByte;
    iss >> nextByte;
    std::cout << nextByte;
    uint8_t ch = nextByte;
    

    一个完整的程序如下:

    #include <sstream>
    #include <iomanip>
    #include <iostream>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    #include <cassert>
    
    typedef std::vector<unsigned char> V;
    
    std::string Stringify(const V& v) {
    
      std::ostringstream oss;
    
      oss << std::hex;
      for(V::const_iterator it = v.begin(); it != v.end(); ++it) {
        oss << std::hex << (unsigned int)*it;
      }
      return oss.str();
    }
    
    
    struct U8 {
      unsigned int datum;
      friend std::istream& operator>>(std::istream&is, U8& u) {
        char s[3] = "xx";
        if(!((is>>s[0]) && (is>>s[1]) && (std::istringstream(s) >> std::hex >> u.datum)))
          is.setstate(std::ios::badbit);
        return is;
      }
      operator unsigned int() const { return datum; }
    };
    
    const V UnStringify(const std::string& str) {
      V v;
      std::istringstream iss(str);
    
      std::copy(std::istream_iterator<U8>(iss),
                std::istream_iterator<U8>(),
                std::back_inserter(v));
    
      return v;
    }
    
    
    int main() {
      V v;
      v.push_back(0x12);
      v.push_back(0x34);
      v.push_back(0xab);
      v.push_back(0xcd);
    
      std::cout << Stringify(v) << "\n";
      assert(v == UnStringify("1234abcd"));
    }
    

    【讨论】:

      【解决方案2】:

      您可以在一个循环中通过一对字符来输入您的 istringstream。我相信 ) 使用 .str()

      【讨论】:

      • 显然不如手动解析效率高,但谁知道呢。我认为至少不会有内存分配。
      【解决方案3】:

      我相信这不是最好的方法,但仍然:

      void BytesToString(unsigned char* bt, char* str)
      {
       int len = sizeof(bt);
      
       for (int i = 0; i < len; i++)
       {
        sprintf(str + i*2, "%2.2x", bt[i]);
       }
      }
      
      void StringToBytes(char* str, unsigned char* bt)
      {
       unsigned int sz = strlen(str);
       if ((sz % 2) == 1)
       {
        //was too lazy to prepend 0 to the string or write a separate case for that one, whatever
      
        puts("Bad input #1");
       }
      
       memset(bt, 0, sz/2);
      
       unsigned char temp = 0;
       for (unsigned int step = 0; step < sz; step++)
       {
        if (str[step] >= 0x30 && str[step] <= 0x39) {temp = (unsigned char)str[step] - 0x30;}
        else
         if (str[step] >= 0x61 && str[step] <= 0x7A) {temp = (unsigned char)str[step] - 0x57;}
              else {/* Is not an ASCII HEX string (illegal character) */   puts("Bad input #2");}
      
        bt[(step - step % 2) / 2] += temp*(0x01 + 0x0F*(!(step % 2)));
       }
      }
      

      【讨论】:

      • “不是真正的 C++”是什么意思?这是 C++。
      • 在 C++ 中使用 C 标准中的函数!= C
      • 如果它看起来像 C,并且像 C 一样工作,那么,它就是 C :) 有时需要混合 C 和 C++ 代码(例如,在实现旧式 API 的 OO 抽象时),但应尽可能避免。我并不是在暗示您的回答是错误的或不好的;但它不是通用的,例如,不适用于任意容器。这是一种 C 方式。
      猜你喜欢
      • 1970-01-01
      • 2011-11-15
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 2014-11-30
      • 1970-01-01
      相关资源
      最近更新 更多