2

Win32 Delphi アプリの一部を別の会社の Linux gcc プログラムで使用できるようにする必要があります。

スループットと展開の要件により、あらゆる種類のリモート サービスが不適切になるため、FreePascal を使用して、gcc アプリが呼び出すことができる .SO (Linux の DLL に相当) を構築することを検討しています。

C/C++ を使用してから長い時間が経ち、Linux では使用したことがないため、gcc 呼び出し元との互換性のために DLL/SO インターフェイスをどのように構築するのが最善かについて少し確信が持てません。

これが私のデータ構造の表現です

TFoo = record
  x, y : double;
  a : smallint;
  b : string;
end;

TBar = record
  a : double;
  b : longint;
  c : string;
end;

TFooBar = record
  foo : array of TFoo;
  bar : array of TBar;
end;

procedure Process(const inFooBar : TFooBar);

この Process メソッドを FreePascal .SO 経由で外部から使用できるようにするには、これらの宣言をどのように変更する必要がありますか? 私はその線に沿って何かを考えています

TFoo = record
  x, y : double;
  a : smallint;
  b : PChar;
end;

TBar = record
  a : double;
  b : longint;
  c : PChar;
end;

TFooBar = record
  foo : ^TFoo;
  foo_count : longint;
  bar : ^TBar;
  bar_count : longint;
end;

procedure Process(const inFooBar : TFooBar);

私は正しい軌道に乗っていますか?私がこれを正確に行う必要はありません。他社のプログラマーが私のミスを修正してくれる可能性が非常に高いです。私が送ったものを見て、彼らがあまり笑ってほしくないだけです。

4

3 に答える 3

1

レコードのパッキング/アライメント/パディングが GCC の期待どおりであることを確認するには、{$packrecords c} を Pascal ソースに追加します。このディレクティブは Free Pascal コンパイラに固有のものであり、Delphi ではサポートされていないことに注意してください。

于 2011-05-25T08:31:45.993 に答える
1

の代わりPAnsiCharPChar、およびのinteger代わりにlongint/smallint使用します (整列されたレコードを使用するため、smallint フィールドを使用する利点はありません)。

PFooやのようないくつかのポインター型を定義しますPBar^TFoo

いくつかの配列にアクセスする必要がある場合は、以下のコードのようにTFooArrayandを定義できます。TBarArray

関数/プロシージャのcdeclor呼び出し規則を忘れないでください。stdcall

type
TFoo = record
  x, y : double;
  a : integer;
  b : PAnsiChar;
end;

TBar = record
  a : double;
  b : integer;
  c : PAnsiChar;
end;

TFooArray = array[0..maxInt div sizeof(TFoo)-1] of TFoo;
TBarArray = array[0..maxInt div sizeof(TBar)-1] of TBar;

PBar = ^TBar;
PFoo = ^TFoo;
PFooArray = ^TFooArray;
PBarArray = ^TBarArray;

TFooBar = record
  foo : PFooArray;
  foo_count : integer;
  bar : PBarArray;
  bar_count : integer;
end;

procedure Process(const inFooBar : TFooBar); cdecl; external 'ProcessGCCLibrary.so';

プロセスは読み取り専用になりますか?

C 部分でいくつかのアイテムを追加する必要がある場合は、外部ライブラリにいくつかのメモリ再割り当てメソッドを提供し、少なくともreallocmem().

Delphi の動的配列は、次のように C 互換の構造に簡単にマッピングできることに注意してください。

type
  TFooDynArray: array of TFoo;
  TBarDynArray: array of TBar;

procedure CallProcess(const aFoo: TFooDynArray; const aBar: TBarDynArray);
var tmp: TFooBar;
begin
  tmp.foo := pointer(aFoo);
  tmp.foo_count := length(aFoo);
  tmp.bar := pointer(aBar);
  tmp.bar_count := length(aBar);
  Process(tmp);
end;

これにより、Delphi コードがはるかに読みやすくなります。のようなメソッドを使用して、このような動的なレコード配列への高レベルのアクセスが必要な場合は、TDynArrayラッパーをご覧ください。TList

AnsiStringタイプは a をマッピングするためPAnsiChar、バイナリの観点から、レコードを次のように定義することもできます。

type
TFoo = record
  x, y : double;
  a : integer;
  b : AnsiString;
end;

TBar = record
  a : double;
  b : integer;
  c : AnsiString;
end;

gcc アプリケーションにマップされると、通常の として読み取られます*char

ここを使用AnsiStringすると、Delphi コードからのメモリ割り当てを処理する必要がなくなります。関連する動的配列を使用すると、Delphi コードの保守がはるかに簡単になります。TDynArray私たちのラッパーは、ネストされたレコードを想定どおりに処理することに注意してください。これAnsiStringは、最高レベルのメソッド (バイナリ シリアル化やハッシュなど) であっても同様です。

于 2011-05-24T06:43:56.110 に答える
0

かなり良さそうです。考え:

  • あなたの配列 (ポインターとカウントとして宣言されている) は、完全に手動で管理されます。それで問題ありませんか?

  • 変更する必要があります:

    procedure Process(const inFooBar : TFooBar);
    

    C 互換の呼び出し規約を含める。FreePascal と GCC の両方が何をサポートしているかはわかりませんが、何か問題なくcdecl動作するはずです。

  • また、(安全のために)構造の配置/パッキングを指定する必要があります。

  • PChar明示的に狭くするか広くする必要があります (最近では広いのが普通です)。

于 2011-05-24T04:54:49.147 に答える