2

パックされたバイナリ データ (構造体の構造体として格納されている) を読み取り、それを Python オブジェクトに解析する Python C 拡張機能を作成しようとしています。すべてが 32 ビット マシン (バイナリ ファイルは常に 32 ビット アーキテクチャで書き込まれます) では期待どおりに動作しますが、64 ビット ボックスでは動作しません。これを行う「好ましい」方法はありますか?


投稿するには多くのコードになりますが、例として:

struct
{
    WORD    version;
    BOOL    upgrade;
    time_t  time1;
            time_t  time2;
} apparms;

File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
  "sysVersion",apparms.version,
  "powerFailTime", apparms.time1,
  "normKitExpDate", apparms.time2
 );

現在、32ビットシステムではこれはうまく機能しますが、64ビットではtime_tのサイズが異なります(32ビットと64ビットの長さ)。


くそー、あなたたちは速いです。

パトリック、私はもともと構造体パッケージを使い始めましたが、私のニーズに合わせて遅くなる方法を見つけました. さらに、Python 拡張機能を作成する言い訳を探していました。

これはばかげた質問だと思いますが、どのようなタイプに注意する必要がありますか?

ありがとう。

4

5 に答える 5

4

データ型 (整数など) が 32 ビットであることを明示的に指定します。それ以外の場合、読み取り時に 2 つの整数が隣り合っている場合、それらは 1 つの 64 ビット整数として読み取られます。

クロスプラットフォームの問題に対処する場合、注意すべき主な点は次の 2 つです。

  1. ビットネス。パックされたデータが 32 ビット int で書き込まれる場合、すべてのコードで読み取りおよび書き込み時に 32 ビット int を明示的に指定する必要があります。
  2. バイト順。コードを Intel チップから PPC または SPARC に移動すると、バイト順序が正しくなくなります。データをインポートしてから、現在のアーキテクチャと一致するようにバイト反転する必要があります。それ以外の場合、12 ( 0x0000000C) は 201326592 ( 0x0C000000) として読み取られます。

うまくいけば、これが役に立ちます。

于 2008-09-25T19:07:22.487 に答える
2

データの途中での構造体の配置は常に問題になりますが、「構造体」モジュールはこれを実行できるはずです。ただし、それを正しく行うのはそれほど難しくありません。structs-in-structs が整列する境界を (1 回) 見つけてから、その境界に ('x' 指定子を使用して手動で) パディングします。struct.calcsize() を実際のデータと比較することで、パディングを再確認できます。そのための C 拡張機能を作成するよりも確かに簡単です。

そのように Py_BuildValue() を使い続けるには、2 つのオプションがあります。コンパイル時に time_t のサイズを決定し (基本型に関しては、'an int' または 'a long' または 'an ssize_t')、次に Py_BuildValue に適切な書式文字を使用できます -- int の場合は 'i'、 long の場合は「l」、ssize_t の場合は「n」。または、PyInt_FromSsize_t() を手動で使用することもできます。この場合、コンパイラがアップキャストを行い、'O' 形式の文字を使用して結果を Py_BuildValue に渡します。

于 2008-09-25T19:03:02.777 に答える
2

構造体にアーキテクチャに依存しないメンバーを使用していることを確認する必要があります。たとえば、あるアーキテクチャでは int が 32 ビットで、別のアーキテクチャでは 64 ビットである場合があります。他の人が示唆しているように、int32_t代わりにスタイルタイプを使用してください。構造体にアライメントされていないメンバーが含まれている場合は、コンパイラによって追加されたパディングも処理する必要がある場合があります。

クロス アーキテクチャ データに関するもう 1 つの一般的な問題は、エンディアンです。Intel i386 アーキテクチャはリトルエンディアンですが、まったく別のマシン (Alpha や Sparc など) で読み込んでいる場合は、これについても心配する必要があります。

Python struct モジュールは、フォーマット文字列の一部として渡されたプレフィックスを使用して、これらの両方の状況に対処します。

  • @ - ネイティブのサイズ、エンディアン、アライメントを使用します。i= sizeof(int)、l= sizeof(long)
  • = - ネイティブのエンディアンを使用しますが、標準のサイズと配置 (i=32 ビット、l=64 ビット)
  • < - リトルエンディアンの標準サイズ/配置
    • ビッグエンディアンの標準サイズ/アライメント

一般に、データがマシンから渡される場合は、エンディアンとサイズ/パディング形式を特定のものに限定する必要があります。「<」または「>」をフォーマットとして使用してください。これを C 拡張機能で処理したい場合は、それを処理するためのコードを追加する必要がある場合があります。

于 2008-09-25T19:15:52.700 に答える
1

バイナリ データを読み取るためのコードは何ですか? int32_tだけではなく、適切なサイズの型にデータをコピーしていることを確認してくださいint

于 2008-09-25T19:02:00.940 に答える
0

structパッケージを使用しないのはなぜですか?

于 2008-09-25T19:02:20.550 に答える