【问题标题】:C++ equivalent of Java ByteBuffer?C++ 等效于 Java ByteBuffer?
【发布时间】:2010-11-30 19:21:03
【问题描述】:

我正在寻找 Java ByteBuffer 的 C++“等效”。

我可能遗漏了明显的内容,或者只需要一个孤立的用法示例来澄清。我浏览了 iostream 系列,看起来它可以提供一个基础。具体来说,我希望能够:

  • 从字节数组/点构建缓冲区并从缓冲区获取原语,例如getByte,getInt
  • 使用原语构建缓冲区,例如putByte, putInt 然后得到字节数组/指针。

【问题讨论】:

  • 请务必注意,在get(T)put(T) 中,T 不是 byte。它是其他原始类型,例如intfloatshort
  • 是的,对我来说,这是一个不幸的命名选择。我已经说得更清楚了。

标签: java c++ bytebuffer


【解决方案1】:

你有stringbuffilebuf,或者你可以使用vector<char>


这是一个使用stringbuf的简单示例:

std::stringbuf buf;
char data[] = {0, 1, 2, 3, 4, 5};
char tempbuf[sizeof data];

buf.sputn(data, sizeof data); // put data
buf.sgetn(tempbuf, sizeof data); // get data

感谢@Pete Kirkham 提出泛型函数的想法。

#include <sstream>

template <class Type>
std::stringbuf& put(std::stringbuf& buf, const Type& var)
{
    buf.sputn(reinterpret_cast<const char*>(&var), sizeof var);

    return buf;
}

template <class Type>
std::stringbuf& get(std::stringbuf& buf, Type& var)
{
    buf.sgetn(reinterpret_cast<char*>(&var), sizeof(var));

    return buf;
}

int main()
{
    std::stringbuf mybuf;
    char byte = 0;
    int var;

    put(mybuf, byte++);
    put(mybuf, byte++);
    put(mybuf, byte++);
    put(mybuf, byte++);

    get(mybuf, var);
}

【讨论】:

  • 如果从缓冲区中提取的东西不是另一个字符数组,这将是一个更好的例子。 ByteBuffer 允许从字节缓冲区中提取 other 原始类型,而不仅仅是字节。 java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html
  • 我选择的 get(T) 和 put(T) 作为例子是相当差的;我想从缓冲区中提取可变大小。 std::stringbuf 感觉是正确的方向。谢谢。
  • 它不是基于字符的。在这种情况下,也许 std::streambuf 是一个更好的选择,尽管它们都应该是可行的。
  • 啊哈。 streambuf 是一个抽象类, stringbuf 只是称为 stringbuf 但这并不意味着它是基于字符的。它只是一个字节缓冲区。但是元素的类型是 char 这就是为什么称为 (string)buf.
【解决方案2】:
std::vector<char> bytes;

bytes.push_back( some_val ); // put

char x = bytes[N];           // get

const char* ptr = &bytes[0]; // pointer to array

【讨论】:

    【解决方案3】:

    对于 std::vector 更有效的是方法

    push_back(T) 
    

    你可以在这里找到更多:

    http://www.cppreference.com/wiki/stl/vector/start

    以及关于 cpp stl 库的一般信息

    http://www.cppreference.com/wiki/stl/start

    容器有很多,看你需要什么,

    • 速度聚合(快速写入能力) 或
    • 快速读取

    看看std::list、std::vector。

    【讨论】:

      【解决方案4】:

      stringstream 提供基本的未格式化getwrite 操作来写入字符块。专注于 T 的子类或包装它,或提供独立的模板函数以使用获取/写入适当大小的内存。

      template <typename T>
      std::stringstream& put ( std::stringstream& str, const T& value )
      {
          union coercion { T value; char   data[ sizeof ( T ) ]; };
      
          coercion    c;
      
          c.value = value;
      
          str.write ( c.data, sizeof ( T ) );
      
          return str;
      }
      
      template <typename T>
      std::stringstream& get ( std::stringstream& str, T& value )
      {
          union coercion { T value; char   data[ sizeof ( T ) ]; };
      
          coercion    c;
      
          c.value = value;
      
          str.read ( c.data, sizeof ( T ) );
      
          value = c.value;
      
          return str;
      }
      

      您可以为您想要的任何其他流或向量编写此类模板 - 在向量的情况下,它需要使用插入而不是写入。

      【讨论】:

      • 不错的解决方案 :) 我认为流更像是一种读取和写入格式化数据的工具。为什么我要使用像缓冲区这样的流,在流内部有一个缓冲区。不过,我认为你的通用函数是个好主意。
      • 我更喜欢流,因为我喜欢强制转换为 bool 和返回流以进行链接的习惯用法,而不是缓冲区返回写入的字节数并不得不摆弄测试。
      【解决方案5】:

      感谢所有的输入,它导致了这个非常简单的解决方案:

      
      class ByteBuffer : std::stringbuf
      {
      public:
          template 
          size_t get( T &out)
          {
              union coercion { T value; char data[ sizeof ( T ) ]; };
      
              coercion c;
      
              size_t s= xsgetn( c.data, sizeof(T));
      
              out= c.value;
      
              return s;
          }
      
          template 
          size_t put( T &in)
          {   
              union coercion { T value; char data[ sizeof ( T ) ]; };
      
              coercion c;
      
              c.value= in;
      
              return xsputn( c.data, sizeof(T));
          }
      
          size_t get( uint8_t *out, size_t count)
          {
              return xsgetn((char *)out, count);
          }
      
          size_t put( uint8_t *out, size_t count)
          {
              return xsputn((char *)out, count);
          }
      };
      

      使用例如:

      
      void ByteBufferTest( void)
      {
          ByteBuffer bb;
      
          float f= 4;
          uint8_t u8= 1;
          uint16_t u16= 2;
          uint32_t u32= 4;
          uint64_t u64= 8;
      
          bb.put(f);
          bb.put(u8);
          bb.put(u16);
          bb.put(u32);
          bb.put(u64);
      
          uint8_t array[19];
      
          bb.get( array, 19);
      
          // or
      
          bb.get(f);
          bb.get(u8);
          bb.get(u16);
          bb.get(u32);
          bb.get(u64);
      }
      

      【讨论】:

      • -1:我真的不喜欢您将 std::stringbuf 子类化的想法。改用合成。该命名空间中的大多数类型都不是为此而设计的。还有,你为什么这样用size_t?
      【解决方案6】:

      我写这篇文章是为了完全按照您的要求进行。试一试:

      https://github.com/RamseyK/ByteBufferCpp

      【讨论】:

      • 如果写入器和读取器在不同的架构上运行,这似乎无法处理整数类型的字节顺序差异。我认为 Java 的 ByteBuffer 默认为大端,但提供了更改字节顺序的能力。有其他选择吗?
      猜你喜欢
      • 1970-01-01
      • 2011-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      相关资源
      最近更新 更多