10

私の知る限り、C ライブラリは、数値を非テキスト バイト ストリームにシリアライズする際に何の助けにもなりません。私が間違っている場合は修正してください。

使用されている最も標準的なツールはhtonl、POSIX の et al です。これらの関数には欠点があります。

  • 64 ビットのサポートはありません。
  • 浮動小数点はサポートされていません。
  • 署名された型のバージョンはありません。逆シリアル化する場合、符号なしから符号付きへの変換は、UB である符号付き整数オーバーフローに依存します。
  • それらの名前は、データ型のサイズを示していません。
  • それらは、8 ビットのバイトと正確なサイズの uint_ N _tの存在に依存します。
  • バイト ストリームを参照する代わりに、入力の型は出力の型と同じです。
    • これには、アラインメントが安全ではない可能性のあるポインターの型キャストを実行する必要があります。
    • その型キャストを実行した後、ユーザーはネイティブ メモリ レイアウトで構造体を変換して出力しようとする可能性が高く、予期しないエラーが発生する不適切な方法です。

任意のサイズcharを 8 ビット標準バイトにシリアル化するためのインターフェイスは、実際には 8 ビット バイトを認識しない C 標準と、伝送の基本単位としてオクテットを設定する標準 (ITU?) との間に分類されます。しかし、古い基準は改訂されていません。

C11 には多くのオプション コンポーネントがあるため、既存の実装に要求を課すことなく、バイナリ シリアル化拡張機能をスレッドなどと一緒に追加できます。

そのような拡張機能は有用でしょうか?それとも非 2 の補数マシンについて心配することは無意味なのでしょうか?

4

3 に答える 3

6

私はそれらを使用したことはありませんが、Google のProtocol Buffersが要件を満たしていると思います。

  • 64 ビット型、符号付き/符号なし、および浮動小数点型がすべてサポートされています。
  • 生成された API はタイプセーフです
  • ストリームとの間でシリアル化を行うことができます

このチュートリアルはかなり良い入門書のように思えます。実際のバイナリ ストレージ形式については、こちらを参照してください。


彼らのウェブページから:

プロトコル バッファとは

プロトコル バッファは、構造化データをシリアライズするための Google の言語中立、プラットフォーム中立、拡張可能なメカニズムです。XML を考えてみてください。データをどのように構造化するかを一度定義すると、特別に生成されたソース コードを使用して、Java、C++、または Python などのさまざまな言語を使用して、さまざまなデータ ストリームとの間で構造化データを簡単に読み書きできます。

純粋な C (C++ のみ) での公式の実装はありませんが、ニーズに合った C ポートが 2 つあります。

8 ビット以外のバイトが存在する場合にどのように動作するかはわかりませんが、比較的簡単に見つけることができるはずです。

于 2012-07-24T01:50:22.147 に答える
4

私の意見では、関数 like の主な欠点は、htonl()シリアル化の半分の作業しか行わないことです。マシンがリトルエンディアンの場合、マルチバイト整数でバイトを反転するだけです。シリアライズ時に実行しなければならないもう 1 つの重要なことは、アライメントの処理ですが、これらの関数はそれを行いません。

多くの CPU は、アドレスがバイト単位の整数の倍数ではないメモリ位置に格納されていないマルチバイト整数に (効率的に) アクセスできません。これが、構造体オーバーレイを使用してネットワーク パケットを (非) シリアル化しない理由です。これが「インプレース変換」の意味かどうかはわかりません。

私は組み込みシステムで多くの作業を行っており、ネットワーク パケット (またはその他の I/O: ディスク、RS232 など) を生成または解析するときに常に使用する独自のライブラリに関数があります。

/* Serialize an integer into a little or big endian byte buffer, resp. */
void SerializeLeInt(uint64_t value, uint8_t *buffer, size_t nrBytes);
void SerializeBeInt(uint64_t value, uint8_t *buffer, size_t nrBytes);

/* Deserialize an integer from a little or big endian byte buffer, resp. */
uint64_t DeserializeLeInt(const uint8_t *buffer, size_t nrBytes);
uint64_t DeserializeBeInt(const uint8_t *buffer, size_t nrBytes);

これらの関数に加えて、次のように定義された一連のマクロがあります。

#define SerializeBeInt16(value, buffer)     SerializeBeInt(value, buffer, sizeof(int16_t))
#define SerializeBeUint16(value, buffer)    SerializeBeInt(value, buffer, sizeof(uint16_t))
#define DeserializeBeInt16(buffer)          DeserializeBeType(buffer, int16_t)
#define DeserializeBeUint16(buffer)         DeserializeBeType(buffer, uint16_t)

(デ) シリアル化関数は値をバイト単位で読み書きするため、アラインメントの問題は発生しません。署名についても心配する必要はありません。まず第一に、最近のすべてのシステムは 2 の補数を使用します (いくつかの ADC を除いて、おそらくこれらの関数は使用されません)。ただし、(私の知る限り)符号付き整数は符号なしにキャストされると2の補数に変換されるため(および関数は符号なし整数を受け入れ/返すため)、1の補数を使用するシステムでも機能するはずです。

あなたの別の議論は、それらが8ビットバイトとexact-sizeの存在に依存しているということですuint_N_t。これは私の関数にも当てはまりますが、私の意見では、これは問題ではありません (これらの型は、私が使用するシステムとそのコンパイラに対して常に定義されています)。関数プロトタイプを調整して、必要に応じて or の代わりに使用するunsigned charこともできます。uint8_tlong longuint_least64_tuint64_t

于 2012-07-23T13:56:10.707 に答える
1

xdrライブラリと XDR 標準RFC-1014 RFC-4506を参照してください。

于 2012-07-23T14:12:03.743 に答える