主机字节序与网络字节序转换

 代码抄写自google quic项目,留为己用。
 byte_codec.h

#pragma  once
#include <algorithm>
#include <cstdint>
#include <type_traits>
namespace base{
enum Endianness {
  NETWORK_BYTE_ORDER,  // big endian
  HOST_BYTE_ORDER      // little endian
};
class DataWriter{
public:
  // Creates a DataWriter where |buffer| is not owned
  // using NETWORK_BYTE_ORDER endianness.
  DataWriter(size_t size, char* buffer);
  // Creates a DataWriter where |buffer| is not owned
  // using the specified endianness.
  DataWriter(size_t size, char* buffer, Endianness endianness);
  DataWriter(const DataWriter&) = delete;
  DataWriter& operator=(const DataWriter&) = delete;

  ~DataWriter();

  // Returns the size of the DataWriter's data.
  size_t length() const { return length_; }

  // Retrieves the buffer from the DataWriter without changing ownership.
  char* data();

  // Methods for adding to the payload.  These values are appended to the end
  // of the DataWriter payload.

  // Writes 8/16/32/64-bit unsigned integers.
  bool WriteUInt8(uint8_t value);
  bool WriteUInt16(uint16_t value);
  bool WriteUInt32(uint32_t value);
  bool WriteUInt64(uint64_t value);

  bool WriteBytes(const void* data, size_t data_len);
  // Advance the writer's position for writing by |length| bytes without writing
  // anything. This method only makes sense to be used on a buffer that has
  // already been written to (and is having certain parts rewritten).
  bool Seek(size_t length);
  size_t capacity() const { return capacity_; }

  size_t remaining() const { return capacity_ - length_; }

 protected:
  // Returns the location that the data should be written at, or nullptr if
  // there is not enough room. Call EndWrite with the returned offset and the
  // given length to pad out for the next write.
  char* BeginWrite(size_t length);

  Endianness endianness() const { return endianness_; }

  char* buffer() const { return buffer_; }

  void IncreaseLength(size_t delta) {
    length_ += delta;
  }

 private:
  // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not
  // char.
  char* buffer_;
  size_t capacity_;  // Allocation size of payload (or -1 if buffer is const).
  size_t length_;    // Current length of the buffer.

  // The endianness to write integers and floating numbers.
  Endianness endianness_;
};
class DataReader{
 public:
  // Constructs a reader using NETWORK_BYTE_ORDER endianness.
  // Caller must provide an underlying buffer to work on.
  DataReader(const char* data, const size_t len);
  // Constructs a reader using the specified endianness.
  // Caller must provide an underlying buffer to work on.
  DataReader(const char* data,
                   const size_t len,
                   Endianness endianness);
  DataReader(const DataReader&) = delete;
  DataReader& operator=(const DataReader&) = delete;

  // Empty destructor.
  ~DataReader() {}

  // Reads an 8/16/32/64-bit unsigned integer into the given output
  // parameter. Forwards the internal iterator on success. Returns true on
  // success, false otherwise.
  bool ReadUInt8(uint8_t* result);
  bool ReadUInt16(uint16_t* result);
  bool ReadUInt32(uint32_t* result);
  bool ReadUInt64(uint64_t* result);
  
  // Reads a given number of bytes into the given buffer. The buffer
  // must be of adequate size.
  // Forwards the internal iterator on success.
  // Returns true on success, false otherwise.
  bool ReadBytes(void* result, size_t size);

  // Skips over |size| bytes from the buffer and forwards the internal iterator.
  // Returns true if there are at least |size| bytes remaining to read, false
  // otherwise.
  bool Seek(size_t size);

  // Returns true if the entirety of the underlying buffer has been read via
  // Read*() calls.
  bool IsDoneReading() const;
  // Returns the number of bytes remaining to be read.
  size_t BytesRemaining() const;
  // DOES NOT forward the internal iterator.
  uint8_t PeekByte() const;
 protected:
  // Returns true if the underlying buffer has enough room to read the given
  // amount of bytes.
  bool CanRead(size_t bytes) const;

  // To be called when a read fails for any reason.
  void OnFailure();

  const char* data() const { return data_; }

  size_t pos() const { return pos_; }

  void AdvancePos(size_t amount) {
    pos_ += amount;
  }

  Endianness endianness() const { return endianness_; }

 private:
  // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not
  // char. The data buffer that we're reading from.
  const char* data_;

  // The length of the data buffer that we're reading from.
  size_t len_;

  // The location of the next read from our data buffer.
  size_t pos_;

  // The endianness to read integers and floating numbers.
  Endianness endianness_;
};
}

 byte_codec.cc

#include <assert.h>
#include <memory.h>
#include "byte_codec.h"
namespace base{
// Provide utility functions that convert from/to network order (big endian)
// to/from host order (little endian).
class  EndianUtil{
 public:
  // Convert |x| from host order (little endian) to network order (big endian).
#if defined(__clang__) || \
    (defined(__GNUC__) && \
     ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
  static uint16_t HostToNet16(uint16_t x) { return __builtin_bswap16(x); }
  static uint32_t HostToNet32(uint32_t x) { return __builtin_bswap32(x); }
  static uint64_t HostToNet64(uint64_t x) { return __builtin_bswap64(x); }
#else
  static uint16_t HostToNet16(uint16_t x) { return PortableByteSwap(x); }
  static uint32_t HostToNet32(uint32_t x) { return PortableByteSwap(x); }
  static uint64_t HostToNet64(uint64_t x) { return PortableByteSwap(x); }
#endif

  // Convert |x| from network order (big endian) to host order (little endian).
  static uint16_t NetToHost16(uint16_t x) { return HostToNet16(x); }
  static uint32_t NetToHost32(uint32_t x) { return HostToNet32(x); }
  static uint64_t NetToHost64(uint64_t x) { return HostToNet64(x); }

  // Left public for tests.
  template <typename T>
  static T PortableByteSwap(T input) {
    static_assert(std::is_unsigned<T>::value, "T has to be uintNN_t");
    union {
      T number;
      char bytes[sizeof(T)];
    } value;
    value.number = input;
    std::reverse(std::begin(value.bytes), std::end(value.bytes));
    return value.number;
  }
};
DataWriter::DataWriter(size_t size, char* buffer)
    : DataWriter(size, buffer, NETWORK_BYTE_ORDER) {}

DataWriter::DataWriter(size_t size,
                                   char* buffer,
                                   Endianness endianness)
    : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {}

DataWriter::~DataWriter() {}

char* DataWriter::data() {
  return buffer_;
}

bool DataWriter::WriteUInt8(uint8_t value) {
  return WriteBytes(&value, sizeof(value));
}

bool DataWriter::WriteUInt16(uint16_t value) {
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    value = EndianUtil::HostToNet16(value);
  }
  return WriteBytes(&value, sizeof(value));
}

bool DataWriter::WriteUInt32(uint32_t value) {
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    value =EndianUtil::HostToNet32(value);
  }
  return WriteBytes(&value, sizeof(value));
}

bool DataWriter::WriteUInt64(uint64_t value) {
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    value = EndianUtil::HostToNet64(value);
  }
  return WriteBytes(&value, sizeof(value));
}
char* DataWriter::BeginWrite(size_t length) {
  if (length_ > capacity_) {
    return nullptr;
  }

  if (capacity_ - length_ < length) {
    return nullptr;
  }
  return buffer_ + length_;
}

bool DataWriter::WriteBytes(const void* data, size_t data_len) {
  char* dest = BeginWrite(data_len);
  if (!dest) {
    return false;
  }

  memcpy(dest, data, data_len);

  length_ += data_len;
  return true;
}
bool DataWriter::Seek(size_t length) {
  if (!BeginWrite(length)) {
    return false;
  }
  length_ += length;
  return true;
}
DataReader::DataReader(const char* data, const size_t len)
    : DataReader(data, len, NETWORK_BYTE_ORDER) {}

DataReader::DataReader(const char* data,
                                   const size_t len,
                                   Endianness endianness)
    : data_(data), len_(len), pos_(0), endianness_(endianness) {}

bool DataReader::ReadUInt8(uint8_t* result) {
  return ReadBytes(result, sizeof(*result));
}

bool DataReader::ReadUInt16(uint16_t* result) {
  if (!ReadBytes(result, sizeof(*result))) {
    return false;
  }
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    *result = EndianUtil::NetToHost16(*result);
  }
  return true;
}

bool DataReader::ReadUInt32(uint32_t* result) {
  if (!ReadBytes(result, sizeof(*result))) {
    return false;
  }
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    *result = EndianUtil::NetToHost32(*result);
  }
  return true;
}

bool DataReader::ReadUInt64(uint64_t* result) {
  if (!ReadBytes(result, sizeof(*result))) {
    return false;
  }
  if (endianness_ ==NETWORK_BYTE_ORDER) {
    *result =EndianUtil::NetToHost64(*result);
  }
  return true;
}
bool DataReader::ReadBytes(void* result, size_t size) {
  // Make sure that we have enough data to read.
  if (!CanRead(size)) {
    OnFailure();
    return false;
  }

  // Read into result.
  memcpy(result, data_ + pos_, size);

  // Iterate.
  pos_ += size;

  return true;
}
bool DataReader::Seek(size_t size) {
  if (!CanRead(size)) {
    OnFailure();
    return false;
  }
  pos_ += size;
  return true;
}

bool DataReader::IsDoneReading() const {
  return len_ == pos_;
}

size_t DataReader::BytesRemaining() const {
  return len_ - pos_;
}
bool DataReader::CanRead(size_t bytes) const {
  return bytes <= (len_ - pos_);
}

void DataReader::OnFailure() {
  // Set our iterator to the end of the buffer so that further reads fail
  // immediately.
  pos_ = len_;
}

uint8_t DataReader::PeekByte() const {
  if (pos_ >= len_) {
    assert(0);
    return 0;
  }
  return data_[pos_];
}
}

 测试例子examples.cc

#include <iostream>
#include <memory.h>
#include "byte_codec.h"
using namespace std;

int main()
{
    char buf[1500];
    uint8_t a=1;
    uint16_t b=1234;
    uint32_t c=43217;
    uint64_t d=1234567890;
    double e=123.44;
    uint64_t double_holder=0;
    memcpy(&double_holder,&e,sizeof(double));
    base::DataWriter w(1500,buf,base::NETWORK_BYTE_ORDER);
    w.WriteUInt8(a);
    w.WriteUInt16(b);
    w.WriteUInt32(c);
    w.WriteUInt64(d);
    w.WriteUInt64(double_holder);
    uint32_t occupied=w.length();
    base::DataReader r(buf,occupied,base::NETWORK_BYTE_ORDER);
    uint8_t a1=0;
    r.ReadUInt8(&a1);
    std::cout<<std::to_string(a1)<<std::endl;
    uint16_t b1=1;
    r.ReadUInt16(&b1);
    std::cout<<"b1 "<<(b1)<<std::endl;
    uint32_t c1=1;
    r.ReadUInt32(&c1);
    std::cout<<"c1 "<<c1<<std::endl;
    uint64_t d1=0;
    r.ReadUInt64(&d1);
    std::cout<<"d1 "<<d1<<std::endl;
    uint64_t double_holder1=0;
    r.ReadUInt64(&double_holder1);
    double e1=0.0;
    memcpy(&e1,&double_holder1,sizeof(double));
    printf("test %f",e1);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值