1

整数に変換する必要がある生のバイナリ データを含む文字列を取得しています。問題は、これらの値が常に同じ順序であるとは限らず、常に表示されるとは限らないことです。そのため、バイナリ データの形式は構成ファイルに記述され、バイナリ データから読み取られる値の型はコンパイル時にはわかりません。

私はこれに似た解決策を考えています:

enum BinaryType {
  TYPE_UINT16,
  TYPE_UNIT32,
  TYPE_INT32
};

long convert(BinaryType t, std::stringstream ss) {
  long return_value;
  switch(t) {
    case TYPE_UINT16:
      unsigned short us_value;
      ss.read(&us_value, sizeof(unsigned short));
      return_value = short;
    break;
    case TYPE_UINT32:
      unsigned int ui_value;
      ss.read(&ui_value, sizeof(unsigned int));
      return_value = ui_value;
    break;
    case TYPE_INT32:
      signed int si_value;
      ss.read(&si_value, sizeof(signed int));
      return_value = si_value;
    break;
  }
  return return_value;
}

目標は、これらの値を 10 進数で出力することです。

私の質問は次のとおりです。

  • このコードは非常に反復的です。もっと簡単な解決策はありますか?(テンプレート?)
  • signed int値を 32 ビットにする必要がある場合など、標準型を使用する必要がありますか? 代わりに何を使用しますか?エンディアン?
4

1 に答える 1

2

A simple solution: define a base class for converters:

class Converter {
public:
virtual int_64 convert(std::stringstream& ss) = 0;
}

Next define a concrete converter for each binary type. Have a map/array mapping from binary types identifiers to your converters, e.g.:

Converter* converters[MAX_BINARY_TYPES];
converters[TYPE_UINT16] = new ConverterUINT16;
...

Now, you can use it like this (variables defined like in your function convert):

cout << converters[t]->convert(ss)

For portability, instead of basic types like int, long, etc, you should use int32_t, int64_t which are guaranteed to be the same on all systems.

Of course, if your code is meant to deal with different endianness, you need to deal with it explicitly. For the above example code you can have two different converters' sets, one for little endian data decoding, another for big endian. Another thing you can do is to write a wrapper class for std::stringstream, let's call it StringStream, which defines functions for reading int32, uint32, etc., and swaps the bytes if the endianness is different than the architecture of the system your code is running on. You can make the class a template and instantiate it with one of the two:

class SameByteOrder {
public:
    template<typename T> static void swap(T &) {}
};

class OtherByteOrder {
public:
    template<typename T> static void swap(T &o)
    {
        char *p = reinterpret_cast<char *>(&o);
        size_t size = sizeof(T);
        for (size_t i=0; i < size / 2; ++i)
            std::swap(p[i], p[size - i - 1]);
    }
};

then use the swap function inside your StringStream's functions to swap (or not) the bytes.

于 2012-11-12T13:23:53.480 に答える