グラフィック エンジン 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プロシージャの___arg1がNULLです。何を試しても、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 でアルゴリズムをマスターする」で見られるように、リストの先頭/末尾へのポインターを含めるつもりだと思います。 . そうすれば、ポインタへのポインタは必要ありません。