3

これはCommon Lisp, CFFI, and instantiating c structsという質問のフォローアップのようなものなので、基本的にこの質問は CFFI を使用した Common Lisp からスタック上の c 関数との間で c 構造体を渡したり返したりすることに関するものです。

上記 (2010 年以降) にリンクされている質問に対する答えは、これは不可能であるというものでした。

CFFI の現在のバージョンは、この質問で説明されているように、libffi を介してスタックで構造体を渡したり返したりすることをサポートしています。ただし、libffi は別の依存関係を導入し、libffi は、私が対象としているすべてのシステムでコンパイルするのは簡単ではありません。したがって、呼び出す関数がほとんどないため、libffi を使用しないようにしています。

リンクした最初の質問で説明したように、構造体を分解することにより、スタック上の構造体パラメーターを期待する C 関数を呼び出すことができます。例として、構造体と関数の定義を次に示します。

typedef struct
{
    int width;        
    int height;       
    bool isGreat; 
} mystruct;

int do_something(mystruct rect);

を使用して Common Lisp からこの関数を呼び出すことができます。

(cffi:defcfun ("do_something" do-something)
    :int
  (width :int)
  (height :int)
  (is-great :boolean))

ここで、2 つの質問があります。

  1. これはすべてのプラットフォームで確実に動作しますか? Cでは、定義により、この状況の構造体は個々のパラメーターとまったく同じようにレイアウトされるため、これが機能することが保証されていると思いますが、よくわかりません。

  2. 構造体を返すのはどうですか?C関数を想定

    mystruct foo();
    

    libffi を使用せずに、Common Lisp から何らかの方法でこれを呼び出す可能性はありますか?たとえば、CFFI に戻り構造が必要とするメモリ量を伝え、それを手動で「解析」することはできますか?

4

1 に答える 1

0

ここにリンクした質問の元の質問者。

私は構造体の分解手法を試しましたが、さまざまな程度の成功を収めました。Windows/Linux x86 では問題なく動作するようですが、これを試してみたときに連携したくないライブラリがいくつかありました (たとえば、アドレスの構造体を受け取った/返したときに libuv を CFFI でラップしようとしていました)。セグメンテーション違反が多い。

ただし、シマリスの場合、この手法は SBCL、CCL、ECL を使用する Windows/Linux でうまく機能しました。ただし、Chipmunk 構造体には 2 つの float メンバーがあり、非常に基本的なものでした。

一般に、構造体が複雑になればなるほど、より多くの問題が発生します。また、これが x86 以外のプラットフォームにどのように移植されるかはわかりません。

最善の策は、バインディングを作成し、ターゲットとする各プラットフォームで試して、何が壊れるかを確認することです。時間があれば、別のオプションとして、ヒープ/スタックを処理する独自の移植可能な C ラッパーを作成することもできます。ライブラリとそのユーザーとの間のもう 1 つのステップであるため、これは好きではありませんが、これまでのところ (シマリスと古いバージョンの libuv を除いて) ポインターを期待する C ライブラリを操作する喜びがありました。

TL;DR:

  1. たぶん、試してみてください。
  2. いいえ。セグメンテーション違反が予想されます。C ライブラリの管理者に電子メールを送信して適切に尋ねると、値の代わりにポインタが得られる場合があります =]。
于 2014-05-12T23:37:30.477 に答える