使用 Erlang 的 NIF,我应该如何在 ERL_NIF_TERM 上使用 malloc?
Using Erlang's NIF, How should I use malloc on ERL_NIF_TERM?
我正在使用 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
中的 double 是否与 ERL_NIF_TERM
中的 int 大小相同?一个 2 个整数的元组也是一个 ERL_NIF_TERM
,它的大小相同吗?
不,您的双精度值和 2,3 元组分配在堆上。它由 env
变量访问。因此,您只需为存储的 ntri
ERL_NIF_TERM
分配 space。它们是您 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;
我正在使用 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
中的 double 是否与 ERL_NIF_TERM
中的 int 大小相同?一个 2 个整数的元组也是一个 ERL_NIF_TERM
,它的大小相同吗?
不,您的双精度值和 2,3 元组分配在堆上。它由 env
变量访问。因此,您只需为存储的 ntri
ERL_NIF_TERM
分配 space。它们是您 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;