0

グラフィック エンジン API を Gambit-C でラップする過程にあり、これまで FFI で成功しています。今日、簡単には乗り越えられない新たな問題に遭遇しました。

私はCでこのような構造を持っています:

typedef struct render_list_rec
{
    long render_id;
    render_node* node;
    struct render_list_rec* next; 
} render_list;

C には、共通のリスト動作を追加するためにマクロによって定義される一連の関数もあります。次に、次のようになります。

void render_list_item_add(render_list_item **list, render_list_item* elem);

C では、NULL の render_list_item* を持つことができますが、それをこの関数の最初のパラメーターに渡すことができ、基本的にリストの先頭を作成します。

私の問題は、Gambit-C の FFI でこの動作を動作させることができないことです。私はこのようなものを作成することになります:

(c-define-type render-list* (pointer (struct "render_list_rec")))
(c-define-type render-list** (pointer (pointer (struct "render_list_rec"))))
(define render-list-add-item (c-lambda (render-list** long render-node*) render-list* "render_list_add_item"))

これを実行すると、セグメンテーション違反が発生します。調査の結果、render -list-add-itemプロシージャの___arg1NULLです。何を試しても、FFI で有効な (ポインター (ポインター)) を取得できません。

これに欠けているものはありますか?

================================================== ==========

完全なスキームの例:

(c-declare #<<c-decl-end
#include <stdio.h>
#include <stdlib.h>

typedef struct test_rec
{
    int i;
} test_rec;

void pointer_test(struct test_rec** in_number)
{
  if (in_number == NULL) {
    fprintf(stdout, "pointer_test is NULL\n");
  }
}

test_rec* new_pointer_test(void)
{
return malloc(sizeof(struct test_rec));
}

c-decl-end
)

(c-define-type test-rec* (pointer (struct "test_rec")))
(define c-pointer-test (c-lambda ((pointer test-rec*)) void "pointer_test"))
(define c-new-pointer-test (c-lambda () test-rec* "new_pointer_test"))
(define test-rec->i-set! (c-lambda (test-rec* int) void "___arg1->i = ___arg2;"))

(display "About to run test with #f ...") (newline)
(define the_false #f)
(c-pointer-test the_false)

(display "About to run test with 1 ...") (newline)
(define number_one (c-new-pointer-test))
(test-rec->i-set! number_one 1)
(c-pointer-test number_one)

コンパイル:

gsc -o test -exe  test.scm

出力を与えます:

About to run test with #f ...
pointer_test is NULL
About to run test with 1 ...
*** ERROR IN ##execute-program -- (Argument 1) Can't convert to C pointer
(c-pointer-test '#<|struct test_rec*| #2 0x28d3fc0>)

================================================== ==========

編集:

Felix: render-list-add-item を呼び出す方法の例をいくつか教えてください

このための C コードは次のようになります。

pg_render_list *ui_render_list = NULL;
pg_render_node *ui_node = pg_font_generate_text_string(app_font, L"Lacunarity:", ui_text_material);
pg_render_list_create_item(&ui_render_list, UI_ID_TEXT, ui_node);

sglibに基づくリスト実装です。上記のように、これらが null ポインターを指すポインターを渡すと、リストの先頭として新しいリスト項目が作成され、*ui_render_list がそれを指すようになります。

スキーム コードは次のようになります (メモリから入力)。

(define ui-render-list #f)
(letrec ((model-data (pg-model-data-read-binary model-filepath))
          (model-node (pg-render-node-create-fom-model model-data GL_STATIC_DRAW)))
  (pg-render-list-item-add ui-render-list model-data))

希望は、同様の動作をすることでした。ドキュメントを見ると、C API に #f があると NULL に変換されるように見えますが、(ポインター (ポインター)) がそれをキャッチする可能性があると思いました。何かにバインドされている変数を渡すことでさえ、常に NULL 値につながりました。ポインターのアドレスを単純に出力する (c-declare) 関数を作成して、これをテストしました。

私の完全なラッパーの動作を見たい場合は、こちらのコミットをご覧ください。

==========================================

(ポインター (ポインター)) をどのように機能させるかという問題はまだ残っています。しかし、より迅速な結果と他の言語との相互運用性を向上させるために、C リスト マクロを書き直してリスト構造を定義し、「C でアルゴリズムをマスターする」で見られるように、リストの先頭/末尾へのポインターを含めるつもりだと思います。 . そうすれば、ポインタへのポインタは必要ありません。

4

1 に答える 1

1

誤解しているかもしれませんが、

(define ui-render-list #f)

次に、次の式だと思います。

(pg-render-list-item-add ui-render-list model-data)

次のように動作します。

pg-render-list-item-add"実際の引数#fとそれが示すものを使って呼び出しmodel-dataます。

そして、Gambit-C FFI は、Schemeから C への境界を越えるときに、Scheme の値#fを C の値NULL(すなわち) に変換します。0

これは、次のものとは大きく異なります。

によって作成されたアイテムの受信者であることを意味する「アドレスとそれを示すものpg-render-list-item-addで呼び出す」。 <addr>model-data<addr>pg-render-list-item-add

C ステートメント:

pg_render_list_create_item(&ui_render_list, UI_ID_TEXT, ui_node);

変数のアドレスui_render_list(たとえば、スタックに割り当てられる可能性があります) を取得し、そのアドレスを に渡しますpg_render_list_create_item。これは、次のように の最初の引数として値を渡すこととは大きく異なります。NULLpg_render_list_create_item

pg_render_list_create_item(ui_render_list, UI_ID_TEXT, ui_node);

アンパサンドがないことに注意してください&。ここが決定的な違いです。

私はあなたの例をGambit-Cで自分で書こうとする時間はまだ取っていませんが、あなたが望む効果を達成できる1つの方法は、(mallocFFIの関数にフックすることによって)受信メモリを自分で割り当てることだと思います.メモリを割り当てると、最初のパラメータとして に渡すことができるアドレスが得られますpg-render-list-item

于 2013-03-05T13:02:33.037 に答える