我正在用Gambit-C包装我的图形引擎API,到目前为止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>)============================================================
编辑:
费利克斯:你能举几个例子来说明你是如何调用呈现列表添加项的吗?
用于此的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);它是基于沙利布的列表实现。当它们传递指向空指针的指针时,如上面所示,它将创建一个新的列表项作为列表的首项,这样*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))希望能有类似的行为。从文档中可以看出,catch中有一个#f转换为NULL,但我认为(指针(指针))可能会捕捉到这一点。即使传递绑定到某物的变量,也总是会导致空值。我通过在一个(c-声明)中创建一个简单地打印指针地址的函数来测试这一点:
如果您想查看我的完整包装器,可以使用看这里这份承诺。
==========================================
如何使(指针(指针))工作的问题仍然存在。但是我认为为了更快的结果,以及更好的与其他语言的互操作性,我将重写我的C列表宏来定义一个列表结构,该结构将包含指向列表头/尾的指针,如“掌握C的算法”中所示。这样,指针指针就没有必要了。
发布于 2013-03-05 13:02:33
也许我误解了,但当你
(define ui-render-list #f)那么我就会认为这个短语:
(pg-render-list-item-add ui-render-list model-data)会表现得像:
“使用实际参数
#f和任何model-data表示的内容调用model-data。
然后Gambit- C.将方案值#f转换为C值NULL (即0)。
这与以下各点有很大不同:
“用地址
<addr>和任何model-data表示的东西调用<addr>”,其中<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。这与将值NULL作为第一个参数传递给pg_render_list_create_item非常不同,该参数如下所示:
pg_render_list_create_item(ui_render_list, UI_ID_TEXT, ui_node);注意没有符号和&;这是一个关键的区别。
我还没有花时间亲自用Gambit-C编写您的示例,但是我想,您可以通过自己分配接收内存(通过连接到FFI中的malloc函数)来实现您想要的效果,然后,一旦您分配了内存,您就有了一个地址,您可以将其作为第一个参数传递给pg-render-list-item。
https://stackoverflow.com/questions/15170249
复制相似问题