11

ストレージ レイアウトが論理設計と正確に一致する必要があることを考えると、ディスク上のデータ構造を操作する最善の方法を知りたいです。ストレージに特定のレイアウトが必要な場合、構造の配置とパッキングはあまり役に立たないことがわかりました.

この問題に対する私のアプローチは、プロセッサ ディレクティブを使用して構造の (幅) を定義し、論理構造モデルに従うデータを追加した後にディスクに書き込む文字 (バイト) 配列を割り当てるときに幅を使用することです。

例えば:

typedef struct __attribute__((packed, aligned(1))) foo {
   uint64_t some_stuff;
   uint8_t flag;
} foo;

ディスク上で foo を永続化すると、「フラグ」値がデータの最後に来ます。&foo 型で fread を使用してデータを読み取るときに foo を簡単に使用できることを考えると、さらにバイトをいじることなく、通常どおり構造体を使用できます。

代わりに、私はこれを行うことを好みます

#define foo_width sizeof(uint64_t)+sizeof(uint8_t)

uint8_t *foo = calloc(1, foo_width);

foo[0] = flag_value;
memcpy(foo+1, encode_int64(some_value), sizeof(uint64_t));

次に、fwrite と fread を使用してバイトをコミットして読み取りますが、後でそれらをアンパックして、さまざまな論理フィールドに格納されたデータを使用します。

ディスク上のストレージのレイアウトを論理レイアウトと一致させたい場合、どのアプローチを使用するのが最適なのだろうか...これは単なる例です...

バイトのデコード/アンパックとディスク上の表現から構造を直接コピーすることに関して、各方法がどれほど効率的かを誰かが知っている場合は、共有してください。このアプローチでは、データ内のさまざまな境界までバイトをアンパック/トラバースするために多くのループ ロジックが必要になるため、パフォーマンスを犠牲にする必要があります。

ありがとう。

4

3 に答える 3

1

要件に基づいて (外観とパフォーマンスを考慮して)、最初のアプローチの方が優れています。コンパイラが面倒な作業を行うからです。つまり、ツール (この場合はコンパイラ) が特定の機能を提供する場合、ほとんどの場合、ツールの実装は自分の実装よりも効率的であるため、それを独自に実装したくありません。

于 2014-11-19T23:10:29.560 に答える
0

私はあなたの2番目のアプローチに近いものを好みますが、memcpyはありません:

void store_i64le(void *dest, uint64_t value)
{  // Generic version which will work with any platform
  uint8_t *d = dest;
  d[0] = (uint8_t)(value);
  d[1] = (uint8_t)(value >> 8);
  d[2] = (uint8_t)(value >> 16);
  d[3] = (uint8_t)(value >> 24);
  d[4] = (uint8_t)(value >> 32);
  d[5] = (uint8_t)(value >> 40);
  d[6] = (uint8_t)(value >> 48);
  d[7] = (uint8_t)(value >> 56);
}

store_i64le(foo+1, some_value);

典型的な ARM では、上記の store_i64le メソッドは約 30 バイトに変換されます。これは、時間、スペース、および複雑さの妥当なトレードオフです。速度の観点からは最適ではありませんが、非整列書き込みをサポートしない Cortex-M0 のようなものでは、スペースの観点からは最適よりも悪くはありません。記述されたコードは、マシンのバイト順序にまったく依存しないことに注意してください。ハードウェアがアライメントされていない 32 ビット アクセスを一連の 8 ビットおよび 16 ビット アクセスに変換するリトル エンディアン プラットフォームを使用していることがわかっている場合は、メソッドを次のように書き直すことができます。

void store_i64le(void *dest, uint64_t value)
{  // For an x86 or little-endian ARM which can handle unaligned 32-bit loads and stores
  uint32_t *d = dest;
  d[0] = (uint32_t)(value);
  d[1] = (uint32_t)(value >> 32);
}

これは、それが機能するプラットフォームでより高速になります。このメソッドは、一度にバイト単位のバージョンと同じように呼び出されることに注意してください。呼び出し元は、どのアプローチを使用するかについて心配する必要はありません。

于 2014-11-20T03:48:27.467 に答える