使用Erlang的NIF,我应该如何在ERL_NIF_TERM上使用malloc?

时间:2016-02-18 01:59:11

标签: c erlang erlang-nif

我正在使用Erlang的NIF,而C函数的结果是一个数组,我希望以三个元组的元组列表的形式发送回erlang,每个元素都是一个元组两个双打。

创建此数组目前我正在执行此操作:

ans = (ERL_NIF_TERM *)malloc(6*ntri*sizeof(ERL_NIF_TERM));

for (i=0;i<ntri;i++) {
    ans[i] = enif_make_tuple3(env,
            enif_make_tuple2(env,enif_make_double(env,x1[i]),enif_make_double(env,y1[i])),
            enif_make_tuple2(env,enif_make_double(env,x2[i]),enif_make_double(env,y2[i])),
            enif_make_tuple2(env,enif_make_double(env,x3[i]),enif_make_double(env,y3[i]))
    );
}

到目前为止,似乎有效。但这是对的吗? 我的理由是,在数组ans的每个单元格中,我有6个双打,大小为ERL_NIF_TERM,所以我按照这个分配。

但这是真的吗?

我应该算一下元组吗?

ERL_NIF_TERM的大小是多少? ERL_NIF_TERM内的双重内容与ERL_NIF_TERM内的int的大小相同吗? 2个整数的元组也是ERL_NIF_TERM,是否大小相同?

1 个答案:

答案 0 :(得分:3)

不,你的双值和2,3元组是在堆上分配的。它由env变量访问。因此,您只需为您存储的ntri ERL_NIF_TERM分配空间。它们是您enif_make_tuple3电话的结果。您也应该尽可能使用enif_alloc代替malloc(在您自己的代码中)。您的代码应如下所示:

ERL_NIF_TERM *ans = enif_alloc(ntri*sizeof(ERL_NIF_TERM));
if(!ans) return enif_raise_exception(env, enif_make_atom(env, "insufficient_memory"));
// use enif_make_badarg(env) prior to R18

for (i=0;i<ntri;i++) {
    ans[i] = enif_make_tuple3(env,
            enif_make_tuple2(env,enif_make_double(env,x1[i]),enif_make_double(env,y1[i])),
            enif_make_tuple2(env,enif_make_double(env,x2[i]),enif_make_double(env,y2[i])),
            enif_make_tuple2(env,enif_make_double(env,x3[i]),enif_make_double(env,y3[i]))
    );
}

ERL_NIF_TERM result = enif_make_list_from_array(env, ans, ntri);
enif_free(ans);
return result;

现在关于第二个问题,无论如何ERL_NIF_TERM的大小是多少? ERL_NIF_TERM的大小就是您平台上的一个词。它在64b上为8B,在32b或64b上为4B半字。它可以存储在堆栈或寄存器中,因此您不必分配所需的内存,您可以将其作为一个简单的参数传递给函数。

编辑:您根本不需要分配内存。直接构造结果列表更有效。

ERL_NIF_TERM result = enif_make_list(env, 0);

for (i = ntri; i;) {
    i--;
    result = enif_make_list_cell(env,
        enif_make_tuple3(env,
            enif_make_tuple2(env,enif_make_double(env,x1[i]),enif_make_double(env,y1[i])),
            enif_make_tuple2(env,enif_make_double(env,x2[i]),enif_make_double(env,y2[i])),
            enif_make_tuple2(env,enif_make_double(env,x3[i]),enif_make_double(env,y3[i]))
        ),
        result
    );
}

return result;